LCOV - code coverage report
Current view: top level - ves - TD_MultithermalMultibaric.cpp (source / functions) Hit Total Coverage
Test: plumed test coverage Lines: 148 152 97.4 %
Date: 2024-10-11 08:09:47 Functions: 8 9 88.9 %

          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 "GridIntegrationWeights.h"
      25             : #include "core/ActionRegister.h"
      26             : #include "tools/Grid.h"
      27             : #include "core/PlumedMain.h"
      28             : #include "core/Atoms.h"
      29             : #include <cfloat>
      30             : 
      31             : 
      32             : namespace PLMD {
      33             : namespace ves {
      34             : 
      35             : //+PLUMEDOC VES_TARGETDIST TD_MULTITHERMAL_MULTIBARIC
      36             : /*
      37             : Multithermal-multibaric target distribution (dynamic).
      38             : 
      39             : Use the target distribution to sample the multithermal-multibaric ensemble \cite Piaggi-PRL-2019 \cite Okumura-CPL-2004.
      40             : In this way, in a single molecular dynamics simulation one can obtain information
      41             : about the simulated system in a range of temperatures and pressures.
      42             : This range is determined through the keywords MIN_TEMP, MAX_TEMP, MIN_PRESSURE, and MAX_PRESSURE.
      43             : One should also specified the target pressure of the barostat with the keyword PRESSURE.
      44             : 
      45             : The collective variables (CVs) used to construct the bias potential must be:
      46             :   1. the potential energy and the volume or,
      47             :   2. the potential energy, the volume, and an order parameter.
      48             : 
      49             : Other choices of CVs or a different order of the above mentioned CVs are nonsensical.
      50             : The third CV, the order parameter, must be used when the region of the phase diagram under study is crossed by a first order phase transition \cite Piaggi-JCP-2019 .
      51             : 
      52             : The algorithm will explore the free energy at each temperature and pressure up to a predefined free
      53             :  energy threshold \f$\epsilon\f$ specified through the keyword THRESHOLD (in kT units).
      54             : If only the energy and the volume are being biased, i.e. no phase transition is considered, then THRESHOLD can be set to around 5.
      55             : If also an order parameter is used then the THRESHOLD should be greater than the barrier for the transformation in kT.
      56             : For small systems undergoing a freezing transition THRESHOLD is typically between 20 and 50.
      57             : 
      58             : It is also important to specify the number of intermediate temperatures and pressures to consider.
      59             : This is done through the keywords STEPS_TEMP and STEPS_PRESSURE.
      60             : If the number of intermediate temperature and pressures is too small, then holes might appear in the target distribution.
      61             : If it is too large, the performance will deteriorate with no additional advantage.
      62             : 
      63             : We now describe the algorithm more rigorously.
      64             : The target distribution is given by
      65             : \f[
      66             : p(E,\mathcal{V},s)=
      67             :   \begin{cases}
      68             :     1/\Omega_{E,\mathcal{V},s} & \text{if there is at least one } \beta',P' \text{ such} \\
      69             :              & \text{that } \beta' F_{\beta',P'}(E,\mathcal{V},s)<\epsilon \text{ with}  \\
      70             :              & \beta_1>\beta'>\beta_2 \text{ and } P_1<P'<P_2 \\
      71             :     0 & \text{otherwise}
      72             :   \end{cases}
      73             : \f]
      74             : with \f$F_{\beta',P'}(E,\mathcal{V},s)\f$ the free energy as a function of energy \f$E\f$ and volume \f$\mathcal{V}\f$ (and optionally the order parameter \f$s\f$) at temperature \f$\beta'\f$ and pressure \f$P'\f$, \f$\Omega_{E,\mathcal{V},s}\f$ is a normalization constant, and \f$\epsilon\f$ is the THRESHOLD.
      75             : In practice the condition \f$\beta' F_{\beta',P'}(E,\mathcal{V},s)<\epsilon\f$  is checked in equally spaced points in each dimension \f$\beta'\f$ and \f$P'\f$.
      76             : The number of points is determined with the keywords STEPS_TEMP and STEPS_PRESSURE.
      77             : In practice the target distribution is never set to zero but rather to a small value controlled by the keyword EPSILON.
      78             : The small value is e^-EPSILON.
      79             : 
      80             : Much like in the Wang-Landau algorithm \cite wanglandau or in the multicanonical ensemble \cite Berg-PRL-1992 , a flat histogram is targeted.
      81             : The idea behind this choice of target distribution is that all regions of potential energy and volume (and optionally order parameter) that are relevant at all temperatures \f$\beta_1<\beta'<\beta_2\f$ and pressure \f$P_1<P'<P_2\f$ are included in the distribution.
      82             : 
      83             : The free energy at temperature \f$\beta'\f$ and pressure \f$P'\f$ is calculated from the free energy at \f$\beta\f$ and \f$P\f$ using:
      84             : \f[
      85             : \beta' F_{\beta',P'}(E,\mathcal{V},s) = \beta F_{\beta,P}(E,\mathcal{V},s) + (\beta' - \beta) E + (\beta' P' - \beta P ) \mathcal{V} + C
      86             : \f]
      87             : with \f$C\f$ such that \f$F_{\beta',P'}(E_m,\mathcal{V}_m,s_m)=0\f$ with \f$E_{m},\mathcal{V}_m,s_m\f$ the position of the free energy minimum.
      88             : \f$ \beta F_{\beta,P}(E,\mathcal{V},s) \f$ is not know from the start and is instead found during the simulation.
      89             : Therefore \f$ p(E,\mathcal{V},s) \f$ is determined iteratively as done in the well tempered target distribution \cite Valsson-JCTC-2015.
      90             : 
      91             : The output of these simulations can be reweighted in order to obtain information at all temperatures and pressures in the targeted region of Temperature-Pressure plane.
      92             : The reweighting can be performed using the action \ref REWEIGHT_TEMP_PRESS.
      93             : 
      94             : The multicanonical ensemble (fixed volume) can be targeted using \ref TD_MULTICANONICAL.
      95             : 
      96             : \par Examples
      97             : 
      98             : The following input can be used to run a simulation in the multithermal-multibaric ensemble.
      99             : The region of the temperature-pressure plane that will be explored is 260-350 K and 1 bar- 300 MPa.
     100             : The energy and the volume are used as collective variables.
     101             : Legendre polynomials are used to construct the two dimensional bias potential.
     102             : The averaged stochastic gradient descent algorithm is chosen to optimize the VES functional.
     103             : The target distribution is updated every 100 optimization steps (200 ps here) using the last estimation of the free energy.
     104             : 
     105             : \plumedfile
     106             : # Use energy and volume as CVs
     107             : energy: ENERGY
     108             : vol: VOLUME
     109             : 
     110             : # Basis functions
     111             : bf1: BF_LEGENDRE ORDER=10 MINIMUM=-14750 MAXIMUM=-12250
     112             : bf2: BF_LEGENDRE ORDER=10 MINIMUM=6.5 MAXIMUM=8.25
     113             : 
     114             : # Target distribution - 1 bar = 0.06022140857 and 300 MPa = 180.66422571
     115             : TD_MULTITHERMAL_MULTIBARIC ...
     116             :  MIN_TEMP=260
     117             :  MAX_TEMP=350
     118             :  MAX_PRESSURE=180.66422571
     119             :  MIN_PRESSURE=0.06022140857
     120             :  PRESSURE=0.06022140857
     121             :  LABEL=td_multi
     122             : ... TD_MULTITHERMAL_MULTIBARIC
     123             : 
     124             : # Bias expansion
     125             : VES_LINEAR_EXPANSION ...
     126             :  ARG=energy,vol
     127             :  BASIS_FUNCTIONS=bf1,bf2
     128             :  TEMP=300.0
     129             :  GRID_BINS=200,200
     130             :  TARGET_DISTRIBUTION=td_multi
     131             :  LABEL=b1
     132             : ... VES_LINEAR_EXPANSION
     133             : 
     134             : # Optimization algorithm
     135             : OPT_AVERAGED_SGD ...
     136             :   BIAS=b1
     137             :   STRIDE=500
     138             :   LABEL=o1
     139             :   STEPSIZE=1.0
     140             :   FES_OUTPUT=500
     141             :   BIAS_OUTPUT=500
     142             :   TARGETDIST_OUTPUT=500
     143             :   COEFFS_OUTPUT=100
     144             :   TARGETDIST_STRIDE=100
     145             : ... OPT_AVERAGED_SGD
     146             : 
     147             : \endplumedfile
     148             : 
     149             : 
     150             : The multithermal-multibaric target distribution can also be used to explore regions of the phase diagram crossed by first order phase transitions.
     151             : Consider a system of 250 atoms that crystallizes in the FCC crystal structure.
     152             : The region of the temperature-pressure plane that will be explored is 350-450 K and 1bar-1GPa.
     153             : We assume that inside this region we can find the liquid-FCC coexistence line that we would like to obtain.
     154             : In this case in addition to the energy and volume, an order parameter must also be biased.
     155             : The energy, volume, and an order parameter are used as collective variables to construct the bias potential.
     156             : We choose as order parameter the \ref FCCUBIC.
     157             : Legendre polynomials are used to construct the three dimensional bias potential.
     158             : The averaged stochastic gradient descent algorithm is chosen to optimize the VES functional.
     159             : The target distribution is updated every 100 optimization steps (200 ps here) using the last estimation of the free energy.
     160             : 
     161             : \plumedfile
     162             : # Use energy, volume and FCCUBIC as CVs
     163             : energy: ENERGY
     164             : vol: VOLUME
     165             : fcc: FCCUBIC SPECIES=1-256 SWITCH={CUBIC D_0=0.4 D_MAX=0.5} MORE_THAN={RATIONAL R_0=0.45 NN=12 MM=24}
     166             : 
     167             : # Basis functions
     168             : bf1: BF_LEGENDRE ORDER=8 MINIMUM=-26500 MAXIMUM=-23500
     169             : bf2: BF_LEGENDRE ORDER=8 MINIMUM=8.0 MAXIMUM=11.5
     170             : bf3: BF_LEGENDRE ORDER=8 MINIMUM=0.0 MAXIMUM=256.0
     171             : 
     172             : # Target distribution
     173             : TD_MULTITHERMAL_MULTIBARIC ...
     174             :  LABEL=td_multitp
     175             :  MIN_TEMP=350.0
     176             :  MAX_TEMP=450.0
     177             :  MIN_PRESSURE=0.06022140857
     178             :  MAX_PRESSURE=602.2140857
     179             :  PRESSURE=301.10704285
     180             :  SIGMA=250.0,0.1,10.0
     181             :  THRESHOLD=15
     182             :  STEPS_TEMP=20
     183             :  STEPS_PRESSURE=20
     184             : ... TD_MULTITHERMAL_MULTIBARIC
     185             : 
     186             : # Expansion
     187             : VES_LINEAR_EXPANSION ...
     188             :  ARG=energy,vol,fcc.morethan
     189             :  BASIS_FUNCTIONS=bf1,bf2,bf3
     190             :  TEMP=400.0
     191             :  GRID_BINS=40,40,40
     192             :  TARGET_DISTRIBUTION=td_multitp
     193             :  LABEL=b1
     194             : ... VES_LINEAR_EXPANSION
     195             : 
     196             : # Optimization algorithm
     197             : OPT_AVERAGED_SGD ...
     198             :   BIAS=b1
     199             :   STRIDE=500
     200             :   LABEL=o1
     201             :   STEPSIZE=1.0
     202             :   FES_OUTPUT=500
     203             :   BIAS_OUTPUT=500
     204             :   TARGETDIST_OUTPUT=500
     205             :   COEFFS_OUTPUT=100
     206             :   TARGETDIST_STRIDE=500
     207             : ... OPT_AVERAGED_SGD
     208             : 
     209             : \endplumedfile
     210             : 
     211             : */
     212             : //+ENDPLUMEDOC
     213             : 
     214             : class TD_MultithermalMultibaric: public TargetDistribution {
     215             : private:
     216             :   double threshold_, min_temp_, max_temp_;
     217             :   double min_press_, max_press_, press_;
     218             :   double epsilon_;
     219             :   bool smoothening_;
     220             :   std::vector<double> sigma_;
     221             :   unsigned steps_temp_, steps_pressure_;
     222             : public:
     223             :   static void registerKeywords(Keywords&);
     224             :   explicit TD_MultithermalMultibaric(const ActionOptions& ao);
     225             :   void updateGrid() override;
     226             :   double getValue(const std::vector<double>&) const override;
     227           6 :   ~TD_MultithermalMultibaric() {}
     228             :   double GaussianSwitchingFunc(const double, const double, const double) const;
     229             : };
     230             : 
     231             : 
     232       10421 : PLUMED_REGISTER_ACTION(TD_MultithermalMultibaric,"TD_MULTITHERMAL_MULTIBARIC")
     233             : 
     234             : 
     235           3 : void TD_MultithermalMultibaric::registerKeywords(Keywords& keys) {
     236           3 :   TargetDistribution::registerKeywords(keys);
     237           6 :   keys.add("compulsory","THRESHOLD","5","Maximum exploration free energy in kT.");
     238           6 :   keys.add("compulsory","EPSILON","10","The zeros of the target distribution are changed to e^-EPSILON.");
     239           6 :   keys.add("compulsory","MIN_TEMP","Minimum energy.");
     240           6 :   keys.add("compulsory","MAX_TEMP","Maximum energy.");
     241           6 :   keys.add("compulsory","MIN_PRESSURE","Minimum pressure.");
     242           6 :   keys.add("compulsory","MAX_PRESSURE","Maximum pressure.");
     243           6 :   keys.add("compulsory","PRESSURE","Target pressure of the barostat used in the MD engine.");
     244           6 :   keys.add("compulsory","STEPS_TEMP","20","Number of temperature steps.");
     245           6 :   keys.add("compulsory","STEPS_PRESSURE","20","Number of pressure steps.");
     246           6 :   keys.add("optional","SIGMA","The standard deviation parameters of the Gaussian kernels used for smoothing the target distribution. One value must be specified for each argument, i.e. one value per CV. A value of 0.0 means that no smoothing is performed, this is the default behavior.");
     247           3 : }
     248             : 
     249             : 
     250           2 : TD_MultithermalMultibaric::TD_MultithermalMultibaric(const ActionOptions& ao):
     251             :   PLUMED_VES_TARGETDISTRIBUTION_INIT(ao),
     252           2 :   threshold_(5.0),
     253           2 :   min_temp_(0.0),
     254           2 :   max_temp_(1000.0),
     255           2 :   min_press_(0.0),
     256           2 :   max_press_(1000.0),
     257           2 :   epsilon_(10.0),
     258           2 :   smoothening_(true),
     259           2 :   steps_temp_(20),
     260           2 :   steps_pressure_(20)
     261             : {
     262           2 :   log.printf("  Multithermal-multibaric target distribution");
     263           2 :   log.printf("\n");
     264             : 
     265           2 :   log.printf("  Please read and cite ");
     266           4 :   log << plumed.cite("Piaggi and Parrinello, Phys. Rev. Lett. 122 (5), 050601 (2019)");
     267           2 :   log.printf(" and ");
     268           4 :   log << plumed.cite("Piaggi and Parrinello, J. Chem. Phys. 150 (24), 244119 (2019)");
     269           2 :   log.printf("\n");
     270             : 
     271             : 
     272           2 :   parse("THRESHOLD",threshold_);
     273           2 :   if(threshold_<=0.0) {
     274           0 :     plumed_merror(getName()+": the value of the threshold should be positive.");
     275             :   }
     276           2 :   log.printf("  exploring free energy up to %f kT for each temperature and pressure\n",threshold_);
     277           2 :   parse("MIN_TEMP",min_temp_);
     278           2 :   parse("MAX_TEMP",max_temp_);
     279           2 :   log.printf("  temperatures between %f and %f will be explored \n",min_temp_,max_temp_);
     280           2 :   parse("MIN_PRESSURE",min_press_);
     281           2 :   parse("MAX_PRESSURE",max_press_);
     282           2 :   log.printf("  pressures between %f and %f will be explored \n",min_press_,max_press_);
     283           2 :   parse("PRESSURE",press_);
     284           2 :   log.printf("  pressure of the barostat should have been set to %f. Please check this in the MD engine \n",press_);
     285           4 :   parseVector("SIGMA",sigma_);
     286           2 :   if(sigma_.size()==0) smoothening_=false;
     287           2 :   if(smoothening_ && (sigma_.size()<2 || sigma_.size()>3) ) plumed_merror(getName()+": SIGMA takes 2 or 3 values as input.");
     288           2 :   if (smoothening_) {
     289           2 :     log.printf("  the target distribution will be smoothed using sigma values");
     290           7 :     for(unsigned i=0; i<sigma_.size(); ++i) log.printf(" %f",sigma_[i]);
     291           2 :     log.printf("\n");
     292             :   }
     293           2 :   parse("STEPS_TEMP",steps_temp_);
     294           2 :   parse("STEPS_PRESSURE",steps_pressure_);
     295           2 :   log.printf("  %d steps in temperatures and %d steps in pressure will be employed \n",steps_temp_,steps_pressure_);
     296           2 :   steps_temp_ += 1;
     297           2 :   steps_pressure_ += 1;
     298           2 :   parse("EPSILON",epsilon_);
     299           2 :   if(epsilon_<=1.0) {
     300           0 :     plumed_merror(getName()+": the value of epsilon should be greater than 1.");
     301             :   }
     302           2 :   log.printf("  the non relevant regions of the target distribution are set to e^-%f \n",epsilon_);
     303             :   setDynamic();
     304             :   setFesGridNeeded();
     305           2 :   checkRead();
     306           2 : }
     307             : 
     308             : 
     309           0 : double TD_MultithermalMultibaric::getValue(const std::vector<double>& argument) const {
     310           0 :   plumed_merror("getValue not implemented for TD_MultithermalMultibaric");
     311             :   return 0.0;
     312             : }
     313             : 
     314             : 
     315           4 : void TD_MultithermalMultibaric::updateGrid() {
     316           4 :   if (getStep() == 0) {
     317           2 :     if(targetDistGrid().getDimension()>3 || targetDistGrid().getDimension()<2) plumed_merror(getName()+" works only with 2 or 3 arguments, i.e. energy and volume, or energy, volume, and CV");
     318           2 :     if(smoothening_ && sigma_.size()!=targetDistGrid().getDimension()) plumed_merror(getName()+": mismatch between SIGMA dimension and number of arguments");
     319             :     // Use uniform TD
     320           4 :     std::vector<double> integration_weights = GridIntegrationWeights::getIntegrationWeights(getTargetDistGridPntr());
     321             :     double norm = 0.0;
     322       11864 :     for(Grid::index_t l=0; l<targetDistGrid().getSize(); l++) {
     323             :       double value = 1.0;
     324       11862 :       norm += integration_weights[l]*value;
     325       11862 :       targetDistGrid().setValue(l,value);
     326             :     }
     327           2 :     targetDistGrid().scaleAllValuesAndDerivatives(1.0/norm);
     328             :   } else {
     329           2 :     double beta = getBeta();
     330           2 :     double beta_prime_min = 1./(plumed.getAtoms().getKBoltzmann()*min_temp_);
     331           2 :     double beta_prime_max = 1./(plumed.getAtoms().getKBoltzmann()*max_temp_);
     332           2 :     plumed_massert(getFesGridPntr()!=NULL,"the FES grid has to be linked to use TD_MultithermalMultibaric!");
     333             :     // Set all to current epsilon value
     334       11864 :     for(Grid::index_t l=0; l<targetDistGrid().getSize(); l++) {
     335       11862 :       double value = exp(-1.0*epsilon_);
     336       11862 :       targetDistGrid().setValue(l,value);
     337             :     }
     338             :     // Loop over pressures and temperatures
     339          44 :     for(unsigned i=0; i<steps_temp_; i++) {
     340          42 :       double beta_prime=beta_prime_min + (beta_prime_max-beta_prime_min)*i/(steps_temp_-1);
     341         924 :       for(unsigned j=0; j<steps_pressure_; j++) {
     342         882 :         double pressure_prime=min_press_ + (max_press_-min_press_)*j/(steps_pressure_-1);
     343             :         // Find minimum for this pressure and temperature
     344             :         double minval=DBL_MAX;
     345     5232024 :         for(Grid::index_t l=0; l<targetDistGrid().getSize(); l++) {
     346    10462284 :           double energy = targetDistGrid().getPoint(l)[0];
     347    10462284 :           double volume = targetDistGrid().getPoint(l)[1];
     348     5231142 :           double value = getFesGridPntr()->getValue(l);
     349     5231142 :           value = beta*value + (beta_prime-beta)*energy + (beta_prime*pressure_prime-beta*press_)*volume;
     350     5231142 :           if(value<minval) {
     351             :             minval=value;
     352             :           }
     353             :         }
     354             :         // Now check which energies and volumes are below X kt
     355     5232024 :         for(Grid::index_t l=0; l<targetDistGrid().getSize(); l++) {
     356    10462284 :           double energy = targetDistGrid().getPoint(l)[0];
     357    10462284 :           double volume = targetDistGrid().getPoint(l)[1];
     358     5231142 :           double value = getFesGridPntr()->getValue(l);
     359     5231142 :           value = beta*value + (beta_prime-beta)*energy + (beta_prime*pressure_prime-beta*press_)*volume - minval;
     360     5231142 :           if (value<threshold_) {
     361             :             double value = 1.0;
     362       65261 :             targetDistGrid().setValue(l,value);
     363             :           }
     364             :         }
     365             :       }
     366             :     }
     367           2 :     if (smoothening_) {
     368           2 :       std::vector<unsigned> nbin=targetDistGrid().getNbin();
     369           2 :       std::vector<double> dx=targetDistGrid().getDx();
     370           2 :       unsigned dim=targetDistGrid().getDimension();
     371             :       // Smoothening
     372       11864 :       for(Grid::index_t index=0; index<targetDistGrid().getSize(); index++) {
     373       11862 :         std::vector<unsigned> indices = targetDistGrid().getIndices(index);
     374       11862 :         std::vector<double> point = targetDistGrid().getPoint(index);
     375       11862 :         double value = targetDistGrid().getValue(index);
     376       11862 :         if (value>(1-1.e-5)) { // Apply only if this grid point was 1.
     377             :           // Apply gaussians around
     378        1242 :           std::vector<int> minBin(dim), maxBin(dim); // These cannot be unsigned
     379             :           // Only consider contributions less than n*sigma bins apart from the actual distance
     380        4384 :           for(unsigned k=0; k<dim; k++) {
     381        3142 :             int deltaBin=std::floor(6*sigma_[k]/dx[k]);
     382        3142 :             minBin[k]=indices[k] - deltaBin;
     383        3142 :             if (minBin[k] < 0) minBin[k]=0;
     384        3142 :             if (minBin[k] > (nbin[k]-1)) minBin[k]=nbin[k]-1;
     385        3142 :             maxBin[k]=indices[k] + deltaBin;
     386        3142 :             if (maxBin[k] > (nbin[k]-1)) maxBin[k]=nbin[k]-1;
     387             :           }
     388        1242 :           if (dim==2) {
     389        7008 :             for(unsigned l=minBin[0]; l<maxBin[0]+1; l++) {
     390      115632 :               for(unsigned m=minBin[1]; m<maxBin[1]+1; m++) {
     391      109208 :                 std::vector<unsigned> indices_prime(dim);
     392      109208 :                 indices_prime[0]=l;
     393      109208 :                 indices_prime[1]=m;
     394      109208 :                 Grid::index_t index_prime = targetDistGrid().getIndex(indices_prime);
     395      109208 :                 std::vector<double> point_prime = targetDistGrid().getPoint(index_prime);
     396      109208 :                 double value_prime = targetDistGrid().getValue(index_prime);
     397             :                 // Apply gaussian
     398             :                 double gaussian_value = 1;
     399      327624 :                 for(unsigned k=0; k<dim; k++) {
     400      436832 :                   gaussian_value *= GaussianSwitchingFunc(point_prime[k],point[k],sigma_[k]);
     401             :                 }
     402      109208 :                 if (value_prime<gaussian_value) {
     403        2761 :                   targetDistGrid().setValue(index_prime,gaussian_value);
     404             :                 }
     405             :               }
     406             :             }
     407         658 :           } else if (dim==3) {
     408       12352 :             for(unsigned l=minBin[0]; l<maxBin[0]+1; l++) {
     409       84952 :               for(unsigned m=minBin[1]; m<maxBin[1]+1; m++) {
     410      509608 :                 for(unsigned n=minBin[2]; n<maxBin[2]+1; n++) {
     411      436350 :                   std::vector<unsigned> indices_prime(dim);
     412      436350 :                   indices_prime[0]=l;
     413      436350 :                   indices_prime[1]=m;
     414      436350 :                   indices_prime[2]=n;
     415      436350 :                   Grid::index_t index_prime = targetDistGrid().getIndex(indices_prime);
     416      436350 :                   std::vector<double> point_prime = targetDistGrid().getPoint(index_prime);
     417      436350 :                   double value_prime = targetDistGrid().getValue(index_prime);
     418             :                   // Apply gaussian
     419             :                   double gaussian_value = 1;
     420     1745400 :                   for(unsigned k=0; k<dim; k++) {
     421     2618100 :                     gaussian_value *= GaussianSwitchingFunc(point_prime[k],point[k],sigma_[k]);
     422             :                   }
     423      436350 :                   if (value_prime<gaussian_value) {
     424       13789 :                     targetDistGrid().setValue(index_prime,gaussian_value);
     425             :                   }
     426             :                 }
     427             :               }
     428             :             }
     429             :           }
     430             :         }
     431             :       }
     432             :     }
     433             :     // Normalize
     434           4 :     std::vector<double> integration_weights = GridIntegrationWeights::getIntegrationWeights(getTargetDistGridPntr());
     435             :     double norm = 0.0;
     436       11864 :     for(Grid::index_t l=0; l<targetDistGrid().getSize(); l++) {
     437       11862 :       double value = targetDistGrid().getValue(l);
     438       11862 :       norm += integration_weights[l]*value;
     439             :     }
     440           2 :     targetDistGrid().scaleAllValuesAndDerivatives(1.0/norm);
     441             :   }
     442           4 :   updateLogTargetDistGrid();
     443           4 : }
     444             : 
     445             : inline
     446             : double TD_MultithermalMultibaric::GaussianSwitchingFunc(const double argument, const double center, const double sigma) const {
     447     1527466 :   if(sigma>0.0) {
     448     1527466 :     double arg=(argument-center)/sigma;
     449     1527466 :     return exp(-0.5*arg*arg);
     450             :   }
     451             :   else {
     452             :     return 0.0;
     453             :   }
     454             : }
     455             : 
     456             : 
     457             : }
     458             : }

Generated by: LCOV version 1.15