LCOV - code coverage report
Current view: top level - ves - TD_MultithermalMultibaric.cpp (source / functions) Hit Total Coverage
Test: plumed test coverage Lines: 155 164 94.5 %
Date: 2025-12-04 11:19:34 Functions: 5 6 83.3 %

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

Generated by: LCOV version 1.16