LCOV - code coverage report
Current view: top level - drr - colvar_UIestimator.h (source / functions) Hit Total Coverage
Test: plumed test coverage Lines: 291 294 99.0 %
Date: 2020-11-18 11:20:57 Functions: 39 39 100.0 %

          Line data    Source code
       1             : /* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
       2             :     Copyright (c) 2017 of Haochuan Chen (excluding colvar_UIestimator.h)
       3             :     Copyright (c) 2017 of Haohao Fu (colvar_UIestimator.h)
       4             : 
       5             :     This program is free software: you can redistribute it and/or modify
       6             :     it under the terms of the GNU Lesser General Public License as published
       7             :     by the Free Software Foundation, either version 3 of the License, or
       8             :     (at your option) any later version.
       9             : 
      10             :     This program is distributed in the hope that it will be useful,
      11             :     but WITHOUT ANY WARRANTY; without even the implied warranty of
      12             :     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      13             :     GNU Lesser General Public License for more details.
      14             : 
      15             :     You should have received a copy of the GNU Lesser General Public License
      16             :     along with this program.  If not, see <http://www.gnu.org/licenses/>.
      17             : +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */
      18             : #ifndef __PLUMED_drr_colvar_UIestimator_h
      19             : #define __PLUMED_drr_colvar_UIestimator_h
      20             : // The original code(https://github.com/fhh2626/colvars/blob/master/src/colvar_UIestimator.h) has been modified by Haochuan Chen.
      21             : // Modifications:
      22             : // 1. Disable colvars related code.
      23             : // 2. Change boltzmann constant.
      24             : // 3. Change output precision.
      25             : // I(Haochuan Chen) don't know how to maintain this code and how it runs. If you are interested in it, please contact Haohao Fu.
      26             : 
      27             : #include <cmath>
      28             : #include <vector>
      29             : #include <fstream>
      30             : #include <string>
      31             : #include <iomanip>
      32             : #include <limits>
      33             : 
      34             : #include <typeinfo>
      35             : 
      36             : // only for colvar module!
      37             : // when integrated into other code, just remove this line and "...cvm::backup_file(...)"
      38             : // #include "colvarmodule.h"
      39             : 
      40             : namespace PLMD {
      41             : namespace drr {
      42             : 
      43             : namespace UIestimator
      44             : {
      45             : const int Y_SIZE = 21;
      46             : const int HALF_Y_SIZE = 10;
      47             : const double BOLTZMANN = 0.0083144621;
      48             : const int EXTENDED_X_SIZE = HALF_Y_SIZE;
      49             : 
      50          68 : class n_matrix    // spare matrix, stores the distribution matrix of n(x,y)
      51             : {
      52             : public:
      53           8 :   n_matrix() {}
      54           4 :   n_matrix(const std::vector<double> & lowerboundary_p,   // lowerboundary of x
      55             :            const std::vector<double> & upperboundary_p,   // upperboundary of
      56             :            const std::vector<double> & width_p,           // width of x
      57             :            const int y_size)           // size of y, for example, ysize=7, then when x=1, the distribution of y in [-2,4] is considered
      58          12 :     : lowerboundary(lowerboundary_p), upperboundary(upperboundary_p), width(width_p)
      59             :   {
      60           4 :     this->dimension = lowerboundary.size();
      61           4 :     this->y_size = y_size;     // keep in mind the internal (spare) matrix is stored in diagonal form
      62           4 :     this->y_total_size = int(pow(y_size, dimension) + 0.000001);
      63             : 
      64             :     // the range of the matrix is [lowerboundary, upperboundary]
      65           4 :     x_total_size = 1;
      66          16 :     for (int i = 0; i < dimension; i++)
      67             :     {
      68          30 :       x_size.push_back(int((upperboundary[i] - lowerboundary[i]) / width[i] + 0.000001));
      69           6 :       x_total_size *= x_size[i];
      70             :     }
      71             : 
      72             :     // initialize the internal matrix
      73           4 :     matrix.reserve(x_total_size);
      74          68 :     for (int i = 0; i < x_total_size; i++)
      75             :     {
      76          64 :       matrix.push_back(std::vector<int>(y_total_size, 0));
      77             :     }
      78             : 
      79           4 :     temp.resize(dimension);
      80           4 :   }
      81             : 
      82       45034 :   int inline get_value(const std::vector<double> & x, const std::vector<double> & y)
      83             :   {
      84             :     //if (matrix[convert_x(x)][convert_y(x, y)]!=0)
      85             :     //{
      86             :     //std::cout<<convert_x(x)<<" "<<convert_y(x, y)<<" "<<x[0]<<" "<<x[1]<<" "<<y[0]<<" "<<y[1]<<" ";
      87             :     //std::cout<<matrix[convert_x(x)][convert_y(x, y)]<<"sadasfdasaaaaaaaa"<<std::endl;
      88             :     //}
      89       90068 :     return matrix[convert_x(x)][convert_y(x, y)];
      90             :   }
      91             : 
      92             :   void inline set_value(const std::vector<double> & x, const std::vector<double> & y, const int value)
      93             :   {
      94             :     matrix[convert_x(x)][convert_y(x,y)] = value;
      95             :   }
      96             : 
      97          34 :   void inline increase_value(const std::vector<double> & x, const std::vector<double> & y, const int value)
      98             :   {
      99          68 :     matrix[convert_x(x)][convert_y(x,y)] += value;
     100          34 :   }
     101             : 
     102             : private:
     103             :   std::vector<double> lowerboundary;
     104             :   std::vector<double> upperboundary;
     105             :   std::vector<double> width;
     106             :   int dimension;
     107             :   std::vector<int> x_size;       // the size of x in each dimension
     108             :   int x_total_size;              // the size of x of the internal matrix
     109             :   int y_size;                    // the size of y in each dimension
     110             :   int y_total_size;              // the size of y of the internal matrix
     111             : 
     112             :   std::vector<std::vector<int> > matrix;  // the internal matrix
     113             : 
     114             :   std::vector<int> temp;         // this vector is used in convert_x and convert_y to save computational resource
     115             : 
     116       45068 :   int convert_x(const std::vector<double> & x)        // convert real x value to its interal index
     117             :   {
     118      221904 :     for (int i = 0; i < dimension; i++)
     119             :     {
     120      442090 :       temp[i] = int((x[i] - lowerboundary[i]) / width[i] + 0.000001);
     121             :     }
     122             : 
     123             :     int index = 0;
     124      133486 :     for (int i = 0; i < dimension; i++)
     125             :     {
     126       88418 :       if (i + 1 < dimension)
     127             :       {
     128             :         int x_temp = 1;
     129      130050 :         for (int j = i + 1; j < dimension; j++)
     130       86700 :           x_temp *= x_size[j];
     131       86700 :         index += temp[i] * x_temp;
     132             :       }
     133             :       else
     134       90136 :         index += temp[i];
     135             :     }
     136       45068 :     return index;
     137             :   }
     138             : 
     139       45068 :   int convert_y(const std::vector<double> & x, const std::vector<double> & y)        // convert real y value to its interal index
     140             :   {
     141      221904 :     for (int i = 0; i < dimension; i++)
     142             :     {
     143      442090 :       temp[i] = round((round(y[i] / width[i] + 0.000001) - round(x[i] / width[i] + 0.000001)) + (y_size - 1) / 2 + 0.000001);
     144             :     }
     145             : 
     146             :     int index = 0;
     147      133486 :     for (int i = 0; i < dimension; i++)
     148             :     {
     149       88418 :       if (i + 1 < dimension)
     150       86700 :         index += temp[i] * int(pow(y_size, dimension - i - 1) + 0.000001);
     151             :       else
     152       90136 :         index += temp[i];
     153             :     }
     154       45068 :     return index;
     155             :   }
     156             : 
     157      265254 :   double round(double r)
     158             :   {
     159      265254 :     return (r > 0.0) ? floor(r + 0.5) : ceil(r - 0.5);
     160             :   }
     161             : };
     162             : 
     163             : // vector, store the sum_x, sum_x_square, count_y
     164             : template <typename T>
     165         597 : class n_vector
     166             : {
     167             : public:
     168          48 :   n_vector() {}
     169          40 :   n_vector(const std::vector<double> & lowerboundary,   // lowerboundary of x
     170             :            const std::vector<double> & upperboundary,   // upperboundary of
     171             :            const std::vector<double> & width_p,                // width of x
     172             :            const int y_size,           // size of y, for example, ysize=7, then when x=1, the distribution of y in [-2,4] is considered
     173             :            const T & default_value)          //   the default value of T
     174         200 :     :width(width_p)
     175             :   {
     176          40 :     this->dimension = lowerboundary.size();
     177             : 
     178          40 :     x_total_size = 1;
     179         168 :     for (int i = 0; i < dimension; i++)
     180             :     {
     181         256 :       this->lowerboundary.push_back(lowerboundary[i] - (y_size - 1) / 2 * width[i] - 0.000001);
     182         192 :       this->upperboundary.push_back(upperboundary[i] + (y_size - 1) / 2 * width[i] + 0.000001);
     183             : 
     184         256 :       x_size.push_back(int((this->upperboundary[i] - this->lowerboundary[i]) / this->width[i] + 0.000001));
     185          64 :       x_total_size *= x_size[i];
     186             :     }
     187             : 
     188             :     // initialize the internal vector
     189          40 :     vector.resize(x_total_size, default_value);
     190             : 
     191          40 :     temp.resize(dimension);
     192          40 :   }
     193             : 
     194         258 :   const T inline get_value(const std::vector<double> & x)
     195             :   {
     196      159900 :     return vector[convert_x(x)];
     197             :   }
     198             : 
     199         100 :   void inline set_value(const std::vector<double> & x, const T & value)
     200             :   {
     201       18142 :     vector[convert_x(x)] = value;
     202         100 :   }
     203             : 
     204             :   void inline increase_value(const std::vector<double> & x, const T & value)
     205             :   {
     206         308 :     vector[convert_x(x)] += value;
     207             :   }
     208             : private:
     209             :   std::vector<double> lowerboundary;
     210             :   std::vector<double> upperboundary;
     211             :   std::vector<double> width;
     212             :   int dimension;
     213             :   std::vector<int> x_size;       // the size of x in each dimension
     214             :   int x_total_size;              // the size of x of the internal matrix
     215             : 
     216             :   std::vector<T> vector;  // the internal vector
     217             : 
     218             :   std::vector<int> temp;         // this vector is used in convert_x and convert_y to save computational resource
     219             : 
     220       89175 :   int convert_x(const std::vector<double> & x)        // convert real x value to its interal index
     221             :   {
     222      439151 :     for (int i = 0; i < dimension; i++)
     223             :     {
     224      874940 :       temp[i] = int((x[i] - lowerboundary[i]) / width[i] + 0.000001);
     225             :     }
     226             : 
     227             :     int index = 0;
     228      264163 :     for (int i = 0; i < dimension; i++)
     229             :     {
     230      174988 :       if (i + 1 < dimension)
     231             :       {
     232             :         int x_temp = 1;
     233      257439 :         for (int j = i + 1; j < dimension; j++)
     234      171626 :           x_temp *= x_size[j];
     235      171626 :         index += temp[i] * x_temp;
     236             :       }
     237             :       else
     238      178350 :         index += temp[i];
     239             :     }
     240       89175 :     return index;
     241             :   }
     242             : };
     243             : 
     244           8 : class UIestimator      // the implemension of UI estimator
     245             : {
     246             : public:
     247           8 :   UIestimator() {}
     248             : 
     249             :   //called when (re)start an eabf simulation
     250           4 :   UIestimator(const std::vector<double>& lowerboundary_p,
     251             :               const std::vector<double>& upperboundary_p,
     252             :               const std::vector<double>& width_p,
     253             :               const std::vector<double>& krestr_p,                // force constant in eABF
     254             :               const std::string& output_filename_p,              // the prefix of output files
     255             :               const int output_freq_p,
     256             :               const bool restart_p,                              // whether restart from a .count and a .grad file
     257             :               const std::vector<std::string>& input_filename_p,   // the prefixes of input files
     258             :               const double temperature_p)
     259           4 :     : lowerboundary(lowerboundary_p), upperboundary(upperboundary_p),
     260             :       width(width_p), krestr(krestr_p),
     261             :       output_filename(output_filename_p), output_freq(output_freq_p),
     262             :       restart(restart_p), input_filename(input_filename_p),
     263          48 :       temperature(temperature_p)
     264             :   {
     265             : 
     266           4 :     dimension = lowerboundary.size();
     267             : 
     268          16 :     for (int i = 0; i < dimension; i++)
     269             :     {
     270          12 :       sum_x.push_back(n_vector<double>(lowerboundary, upperboundary, width, Y_SIZE, 0.0));
     271          12 :       sum_x_square.push_back(n_vector<double>(lowerboundary, upperboundary, width, Y_SIZE, 0.0));
     272             : 
     273          12 :       x_av.push_back(n_vector<double>(lowerboundary, upperboundary, width, Y_SIZE, 0.0));
     274          12 :       sigma_square.push_back(n_vector<double>(lowerboundary, upperboundary, width, Y_SIZE, 0.0));
     275             :     }
     276             : 
     277           4 :     count_y = n_vector<int>(lowerboundary, upperboundary, width, Y_SIZE, 0);
     278           4 :     distribution_x_y = n_matrix(lowerboundary, upperboundary, width, Y_SIZE);
     279             : 
     280           8 :     grad = n_vector<std::vector<double> >(lowerboundary, upperboundary, width, 1, std::vector<double>(dimension, 0.0));
     281           4 :     count = n_vector<int>(lowerboundary, upperboundary, width, 1, 0);
     282             : 
     283           4 :     written = false;
     284           4 :     written_1D = false;
     285             : 
     286           4 :     if (dimension == 1)
     287             :     {
     288           2 :       std::vector<double> upperboundary_temp = upperboundary;
     289           6 :       upperboundary_temp[0] = upperboundary[0] + width[0];
     290           2 :       oneD_pmf = n_vector<double>(lowerboundary, upperboundary_temp, width, 1, 0.0);
     291             :     }
     292             : 
     293           4 :     if (restart == true)
     294             :     {
     295           2 :       input_grad = n_vector<std::vector<double> >(lowerboundary, upperboundary, width, 1, std::vector<double>(dimension, 0.0));
     296           1 :       input_count = n_vector<int>(lowerboundary, upperboundary, width, 1, 0);
     297             : 
     298             :       // initialize input_Grad and input_count
     299           1 :       std::vector<double> loop_flag(dimension, 0);
     300           5 :       for (int i = 0; i < dimension; i++)
     301             :       {
     302           4 :         loop_flag[i] = lowerboundary[i];
     303             :       }
     304             :       while (true)
     305             :       {
     306          45 :         for (int i = 0; i < dimension; i++)
     307             :         {
     308          36 :           input_grad.set_value(loop_flag, std::vector<double>(dimension,0));
     309             :         }
     310             :         input_count.set_value(loop_flag, 0);
     311             : 
     312             :         // iterate over any dimensions
     313           9 :         int i = dimension - 1;
     314             :         while (true)
     315             :         {
     316          36 :           loop_flag[i] += width[i];
     317          36 :           if (loop_flag[i] > upperboundary[i] - width[i] + 0.00001)
     318             :           {
     319           4 :             loop_flag[i] = lowerboundary[i];
     320           4 :             i--;
     321           4 :             if (i < 0)
     322             :               goto INITIAL_LOOPEND;
     323             :           }
     324             :           else
     325             :             break;
     326             :         }
     327             :       }
     328           1 : INITIAL_LOOPEND:
     329           1 :       read_inputfiles(input_filename);
     330             :     }
     331           4 :   }
     332             : 
     333          16 :   ~UIestimator() {}
     334             : 
     335             :   // called from MD engine every step
     336          34 :   bool update(const int step, std::vector<double> x, std::vector<double> y)
     337             :   {
     338             : 
     339             :     //std::cout<<"weeeee: :"<<std::endl;
     340             :     //for (int i = 0; i < dimension; i++)
     341             :     //{
     342             :     //  std::cout<<x[i]<<" "<<y[i]<<" ";
     343             :     //}
     344             :     //std::cout<<std::endl;
     345             : 
     346          34 :     if (step % output_freq == 0)
     347             :     {
     348          10 :       calc_pmf();
     349          10 :       write_files();
     350             :       //write_interal_data();
     351             :     }
     352             : 
     353         150 :     for (int i = 0; i < dimension; i++)
     354             :     {
     355             :       // for dihedral RC, it is possible that x = 179 and y = -179, should correct it
     356             :       // may have problem, need to fix
     357         116 :       if (x[i] > 150 && y[i] < -150)
     358             :       {
     359             :         //std::vector<double> x_temp(x);
     360             :         //x_temp[i] -= 360;
     361             :         //update(7, x_temp, y);
     362           0 :         y[i] += 360;
     363             :       }
     364          58 :       if (x[i] < -150 && y[i] > 150)
     365             :       {
     366             :         //std::vector<double> x_temp(x);
     367             :         //x_temp[i] += 360;
     368             :         //update(7, x_temp, y);
     369           0 :         y[i] -= 360;
     370             :       }
     371             : 
     372         232 :       if (x[i] < lowerboundary[i] - EXTENDED_X_SIZE * width[i] + 0.00001 || x[i] > upperboundary[i] + EXTENDED_X_SIZE * width[i] - 0.00001 \
     373          58 :           || y[i] - x[i] < -HALF_Y_SIZE * width[i] + 0.00001 || y[i] - x[i] > HALF_Y_SIZE * width[i] - 0.00001 \
     374         116 :           || y[i] - lowerboundary[i] < -HALF_Y_SIZE * width[i] + 0.00001 || y[i] - upperboundary[i] > HALF_Y_SIZE * width[i] - 0.00001)
     375             :         return false;
     376             :     }
     377             : 
     378             :     //for (int i = 0; i < dimension; i++)
     379             :     //{
     380             :     //  std::cout<<x[i]<<" "<<y[i]<<" ";
     381             :     //}
     382             :     //std::cout<<std::endl;
     383             : 
     384         150 :     for (int i = 0; i < dimension; i++)
     385             :     {
     386          58 :       sum_x[i].increase_value(y, x[i]);
     387          58 :       sum_x_square[i].increase_value(y, x[i] * x[i]);
     388             :     }
     389          34 :     count_y.increase_value(y, 1);
     390             : 
     391         150 :     for (int i = 0; i < dimension; i++)
     392             :     {
     393             :       //if (x[i] < lowerboundary[i] + 0.000001 || x[i] > upperboundary[i] - 0.000001)
     394             :       // adapt colvars precision
     395         232 :       if (x[i] < lowerboundary[i] + 0.00001 || x[i] > upperboundary[i] - 0.00001)
     396             :         return false;
     397             :     }
     398          34 :     distribution_x_y.increase_value(x, y, 1);
     399             : 
     400          34 :     return true;
     401             :   }
     402             : 
     403             :   // update the output_filename
     404             :   void update_output_filename(const std::string& filename)
     405             :   {
     406          34 :     output_filename = filename;
     407             :   }
     408             : 
     409             : private:
     410             :   std::vector<n_vector<double> > sum_x;                        // the sum of x in each y bin
     411             :   std::vector<n_vector<double> > sum_x_square;                 // the sum of x in each y bin
     412             :   n_vector<int> count_y;                              // the distribution of y
     413             :   n_matrix distribution_x_y;   // the distribution of <x, y> pair
     414             : 
     415             :   int dimension;
     416             : 
     417             :   std::vector<double> lowerboundary;
     418             :   std::vector<double> upperboundary;
     419             :   std::vector<double> width;
     420             :   std::vector<double> krestr;
     421             :   std::string output_filename;
     422             :   int output_freq;
     423             :   bool restart;
     424             :   std::vector<std::string> input_filename;
     425             :   double temperature;
     426             : 
     427             :   n_vector<std::vector<double> > grad;
     428             :   n_vector<int> count;
     429             : 
     430             :   n_vector<double> oneD_pmf;
     431             : 
     432             :   n_vector<std::vector<double> > input_grad;
     433             :   n_vector<int> input_count;
     434             : 
     435             :   // used in double integration
     436             :   std::vector<n_vector<double> > x_av;
     437             :   std::vector<n_vector<double> > sigma_square;
     438             : 
     439             :   bool written;
     440             :   bool written_1D;
     441             : 
     442             :   // calculate gradients from the internal variables
     443          10 :   void calc_pmf()
     444             :   {
     445             :     int norm;
     446             : 
     447          10 :     std::vector<double> loop_flag(dimension, 0);
     448          38 :     for (int i = 0; i < dimension; i++)
     449             :     {
     450          56 :       loop_flag[i] = lowerboundary[i] - HALF_Y_SIZE * width[i];
     451             :     }
     452             : 
     453             :     while (true)
     454             :     {
     455        4556 :       norm = count_y.get_value(loop_flag) > 0 ? count_y.get_value(loop_flag) : 1;
     456       11066 :       for (int i = 0; i < dimension; i++)
     457             :       {
     458        8788 :         x_av[i].set_value(loop_flag, sum_x[i].get_value(loop_flag) / norm);
     459        8788 :         sigma_square[i].set_value(loop_flag, sum_x_square[i].get_value(loop_flag) / norm - x_av[i].get_value(loop_flag) * x_av[i].get_value(loop_flag));
     460             :       }
     461             : 
     462             :       // iterate over any dimensions
     463        2278 :       int i = dimension - 1;
     464             :       while (true)
     465             :       {
     466        7110 :         loop_flag[i] += width[i];
     467        7110 :         if (loop_flag[i] > upperboundary[i] + HALF_Y_SIZE * width[i] - width[i] + 0.00001)
     468             :         {
     469         102 :           loop_flag[i] = lowerboundary[i] - HALF_Y_SIZE * width[i];
     470         102 :           i--;
     471         102 :           if (i < 0)
     472             :             goto LOOPEND;
     473             :         }
     474             :         else
     475             :           break;
     476             :       }
     477             :     }
     478          10 : LOOPEND:
     479             : 
     480             :     // double integration
     481          10 :     std::vector<double> av(dimension, 0);
     482          10 :     std::vector<double> diff_av(dimension, 0);
     483             : 
     484          10 :     std::vector<double> loop_flag_x(dimension, 0);
     485          10 :     std::vector<double> loop_flag_y(dimension, 0);
     486          38 :     for (int i = 0; i < dimension; i++)
     487             :     {
     488          28 :       loop_flag_x[i] = lowerboundary[i];
     489          42 :       loop_flag_y[i] = loop_flag_x[i] - HALF_Y_SIZE * width[i];
     490             :     }
     491             : 
     492             :     while (true)
     493             :     {
     494             :       norm = 0;
     495         306 :       for (int i = 0; i < dimension; i++)
     496             :       {
     497         228 :         av[i] = 0;
     498         114 :         diff_av[i] = 0;
     499         342 :         loop_flag_y[i] = loop_flag_x[i] - HALF_Y_SIZE * width[i];
     500             :       }
     501             : 
     502             :       while (true)
     503             :       {
     504             :         //std::cout<<"pppppppppppppppppppppp "<<loop_flag_x[0]<<" "<<loop_flag_x[1]<<" "<<loop_flag_y[0]<<" "<<loop_flag_y[1]<<std::endl;
     505       15240 :         norm += distribution_x_y.get_value(loop_flag_x, loop_flag_y);
     506       74520 :         for (int i = 0; i < dimension; i++)
     507             :         {
     508       88766 :           if (sigma_square[i].get_value(loop_flag_y) > 0.00001 || sigma_square[i].get_value(loop_flag_y) < -0.00001)
     509         924 :             av[i] += distribution_x_y.get_value(loop_flag_x, loop_flag_y) * ( (loop_flag_x[i] + 0.5 * width[i]) - x_av[i].get_value(loop_flag_y)) / sigma_square[i].get_value(loop_flag_y);
     510             : 
     511      118560 :           diff_av[i] += distribution_x_y.get_value(loop_flag_x, loop_flag_y) * (loop_flag_x[i] - loop_flag_y[i]);
     512             :         }
     513             : 
     514             :         // iterate over any dimensions
     515       15240 :         int i = dimension - 1;
     516             :         while (true)
     517             :         {
     518       47880 :           loop_flag_y[i] += width[i];
     519       47880 :           if (loop_flag_y[i] > loop_flag_x[i] + HALF_Y_SIZE * width[i] - width[i] + 0.00001)
     520             :           {
     521         798 :             loop_flag_y[i] = loop_flag_x[i] - HALF_Y_SIZE * width[i];
     522         798 :             i--;
     523         798 :             if (i < 0)
     524             :               goto LOOPEND2;
     525             :           }
     526             :           else
     527             :             break;
     528             :         }
     529             :       }
     530          78 : LOOPEND2:
     531             : 
     532          78 :       std::vector<double> grad_temp(dimension, 0);
     533         306 :       for (int i = 0; i < dimension; i++)
     534             :       {
     535         228 :         diff_av[i] /= (norm > 0 ? norm : 1);
     536         228 :         av[i] = BOLTZMANN * temperature * av[i] / (norm > 0 ? norm : 1);
     537         456 :         grad_temp[i] = av[i] - krestr[i] * diff_av[i];
     538             :       }
     539          78 :       grad.set_value(loop_flag_x, grad_temp);
     540          78 :       count.set_value(loop_flag_x, norm);
     541             : 
     542             :       // iterate over any dimensions
     543          78 :       int i = dimension - 1;
     544             :       while (true)
     545             :       {
     546         270 :         loop_flag_x[i] += width[i];
     547         270 :         if (loop_flag_x[i] > upperboundary[i] - width[i] + 0.00001)
     548             :         {
     549          22 :           loop_flag_x[i] = lowerboundary[i];
     550          22 :           i--;
     551          22 :           if (i < 0)
     552             :             goto LOOPEND3;
     553             :         }
     554             :         else
     555             :           break;
     556             :       }
     557             :     }
     558             : LOOPEND3:;
     559          10 :   }
     560             : 
     561             : 
     562             :   // calculate 1D pmf
     563           6 :   void calc_1D_pmf()
     564             :   {
     565           6 :     std::vector<double> last_position(1, 0);
     566           6 :     std::vector<double> position(1, 0);
     567             : 
     568             :     double min = 0;
     569             :     double dG = 0;
     570             : 
     571           6 :     oneD_pmf.set_value(lowerboundary, 0);
     572           6 :     last_position = lowerboundary;
     573         102 :     for (double i = lowerboundary[0] + width[0]; i < upperboundary[0] + 0.000001; i += width[0])
     574             :     {
     575          42 :       position[0] = i + 0.000001;
     576          42 :       if (restart == false || input_count.get_value(last_position) == 0)
     577             :       {
     578         168 :         dG = oneD_pmf.get_value(last_position) + grad.get_value(last_position)[0] * width[0];
     579             :       }
     580             :       else
     581             :       {
     582           0 :         dG = oneD_pmf.get_value(last_position) + ((grad.get_value(last_position)[0] * count.get_value(last_position) + input_grad.get_value(last_position)[0] * input_count.get_value(last_position)) / (count.get_value(last_position) + input_count.get_value(last_position))) * width[0];
     583             :       }
     584          42 :       if (dG < min)
     585             :         min = dG;
     586             :       oneD_pmf.set_value(position, dG);
     587          42 :       last_position[0] = i + 0.000001;
     588             :     }
     589             : 
     590         108 :     for (double i = lowerboundary[0]; i < upperboundary[0] + 0.000001; i += width[0])
     591             :     {
     592          48 :       position[0] = i + 0.000001;
     593          48 :       oneD_pmf.set_value(position, oneD_pmf.get_value(position) - min);
     594             :     }
     595           6 :   }
     596             : 
     597             :   // write 1D pmf
     598           6 :   void write_1D_pmf()
     599             :   {
     600           6 :     std::string pmf_filename = output_filename + ".UI.pmf";
     601             : 
     602             :     // only for colvars module!
     603             : //                      if (written_1D) cvm::backup_file(pmf_filename.c_str());
     604             : 
     605          12 :     std::ofstream ofile_pmf(pmf_filename.c_str());
     606             : 
     607           6 :     std::vector<double> position(1, 0);
     608         108 :     for (double i = lowerboundary[0]; i < upperboundary[0] + 0.000001; i += width[0])
     609             :     {
     610          48 :       ofile_pmf << i << " ";
     611          48 :       position[0] = i + 0.000001;
     612          48 :       ofile_pmf << oneD_pmf.get_value(position) << std::endl;
     613             :     }
     614           6 :     ofile_pmf.close();
     615             : 
     616           6 :     written_1D = true;
     617           6 :   }
     618             : 
     619             :   // write heads of the output files
     620          30 :   void writehead(std::ofstream& os) const
     621             :   {
     622          60 :     os << "# " << dimension << std::endl;
     623         114 :     for (int i = 0; i < dimension; i++)
     624             :     {
     625          42 :       os.precision(std::numeric_limits<double>::max_digits10);
     626         294 :       os << "# " << std::fixed << lowerboundary[i] << " " << width[i] << " " << int((upperboundary[i] - lowerboundary[i]) / width[i] + 0.000001) << " " << 0 << std::endl;
     627             :     }
     628             :     os << std::endl;
     629          30 :   }
     630             : 
     631             :   // write interal data, used for testing
     632             : //   void write_interal_data()
     633             : //   {
     634             : //     std::string internal_filaname = output_filename + ".UI.internal";
     635             : //
     636             : //     std::ofstream ofile_internal(internal_filaname.c_str());
     637             : //
     638             : //     std::vector<double> loop_flag(dimension, 0);
     639             : //     for (int i = 0; i < dimension; i++)
     640             : //     {
     641             : //       loop_flag[i] = lowerboundary[i];
     642             : //     }
     643             : //     while (true)
     644             : //     {
     645             : //       for (int i = 0; i < dimension; i++)
     646             : //       {
     647             : //         ofile_internal << loop_flag[i] + 0.5 * width[i] << " ";
     648             : //       }
     649             : //
     650             : //       for (int i = 0; i < dimension; i++)
     651             : //       {
     652             : //         ofile_internal << grad.get_value(loop_flag)[i] << " ";
     653             : //       }
     654             : //
     655             : //       std::vector<double> ii(dimension,0);
     656             : //       for (double i = loop_flag[0] - 10; i < loop_flag[0] + 10 + 0.00001; i+= width[0])
     657             : //       {
     658             : //         for (double j = loop_flag[1] - 10; j< loop_flag[1] + 10 +0.00001; j+=width[1])
     659             : //         {
     660             : //           ii[0] = i;
     661             : //           ii[1] = j;
     662             : //           ofile_internal << i <<" "<<j<<" "<< distribution_x_y.get_value(loop_flag,ii)<< " ";
     663             : //         }
     664             : //       }
     665             : //       ofile_internal << std::endl;
     666             : //
     667             : //       // iterate over any dimensions
     668             : //       int i = dimension - 1;
     669             : //       while (true)
     670             : //       {
     671             : //         loop_flag[i] += width[i];
     672             : //         if (loop_flag[i] > upperboundary[i] - width[i] + 0.00001)
     673             : //         {
     674             : //           loop_flag[i] = lowerboundary[i];
     675             : //           i--;
     676             : //           if (i < 0)
     677             : //             goto LOOPEND5;
     678             : //         }
     679             : //         else
     680             : //           break;
     681             : //       }
     682             : //     }
     683             : // LOOPEND5:
     684             : //     ofile_internal.close();
     685             : //   }
     686             : 
     687             :   // write output files
     688          10 :   void write_files()
     689             :   {
     690          10 :     std::string grad_filename = output_filename + ".UI.grad";
     691          10 :     std::string hist_filename = output_filename + ".UI.hist.grad";
     692          10 :     std::string count_filename = output_filename + ".UI.count";
     693             : 
     694             :     // only for colvars module!
     695             : //                      if (written) cvm::backup_file(grad_filename.c_str());
     696             :     //if (written) cvm::backup_file(hist_filename.c_str());
     697             : //                      if (written) cvm::backup_file(count_filename.c_str());
     698             : 
     699          20 :     std::ofstream ofile(grad_filename.c_str());
     700          20 :     std::ofstream ofile_hist(hist_filename.c_str(), std::ios::app);
     701          20 :     std::ofstream ofile_count(count_filename.c_str());
     702             : 
     703          10 :     writehead(ofile);
     704          10 :     writehead(ofile_hist);
     705          10 :     writehead(ofile_count);
     706             : 
     707          10 :     if (dimension == 1)
     708             :     {
     709           6 :       calc_1D_pmf();
     710           6 :       write_1D_pmf();
     711             :     }
     712             : 
     713          10 :     std::vector<double> loop_flag(dimension, 0);
     714          38 :     for (int i = 0; i < dimension; i++)
     715             :     {
     716          28 :       loop_flag[i] = lowerboundary[i];
     717             :     }
     718             :     while (true)
     719             :     {
     720         306 :       for (int i = 0; i < dimension; i++)
     721             :       {
     722         456 :         ofile << std::fixed << std::setprecision(9) << loop_flag[i] + 0.5 * width[i] << " ";
     723         342 :         ofile_hist << std::fixed << std::setprecision(9) << loop_flag[i] + 0.5 * width[i] << " ";
     724         342 :         ofile_count << std::fixed << std::setprecision(9) << loop_flag[i] + 0.5 * width[i] << " ";
     725             :       }
     726             : 
     727          78 :       if (restart == false)
     728             :       {
     729         216 :         for (int i = 0; i < dimension; i++)
     730             :         {
     731         312 :           ofile << std::fixed << std::setprecision(9) << grad.get_value(loop_flag)[i] << " ";
     732         312 :           ofile_hist << std::fixed << std::setprecision(9) << grad.get_value(loop_flag)[i] << " ";
     733             :         }
     734             :         ofile << std::endl;
     735             :         ofile_hist << std::endl;
     736         120 :         ofile_count << count.get_value(loop_flag) << " " <<std::endl;
     737             :       }
     738             :       else
     739             :       {
     740             :         double final_grad = 0;
     741          90 :         for (int i = 0; i < dimension; i++)
     742             :         {
     743         108 :           int total_count_temp = (count.get_value(loop_flag) + input_count.get_value(loop_flag));
     744          36 :           if (input_count.get_value(loop_flag) == 0)
     745          60 :             final_grad = grad.get_value(loop_flag)[i];
     746             :           else
     747         112 :             final_grad = ((grad.get_value(loop_flag)[i] * count.get_value(loop_flag) + input_grad.get_value(loop_flag)[i] * input_count.get_value(loop_flag)) / total_count_temp);
     748          36 :           ofile << std::fixed << std::setprecision(9) << final_grad << " ";
     749          36 :           ofile_hist << std::fixed << std::setprecision(9) << final_grad << " ";
     750             :         }
     751             :         ofile << std::endl;
     752             :         ofile_hist << std::endl;
     753          54 :         ofile_count << (count.get_value(loop_flag) + input_count.get_value(loop_flag)) << " " <<std::endl;
     754             :       }
     755             : 
     756             :       // iterate over any dimensions
     757          78 :       int i = dimension - 1;
     758             :       while (true)
     759             :       {
     760         270 :         loop_flag[i] += width[i];
     761         270 :         if (loop_flag[i] > upperboundary[i] - width[i] + 0.00001)
     762             :         {
     763          22 :           loop_flag[i] = lowerboundary[i];
     764          22 :           i--;
     765             :           ofile << std::endl;
     766             :           ofile_hist << std::endl;
     767             :           ofile_count << std::endl;
     768          22 :           if (i < 0)
     769             :             goto LOOPEND4;
     770             :         }
     771             :         else
     772             :           break;
     773             :       }
     774             :     }
     775          10 : LOOPEND4:
     776          10 :     ofile.close();
     777          10 :     ofile_count.close();
     778          10 :     ofile_hist.close();
     779             : 
     780          10 :     written = true;
     781          10 :   }
     782             : 
     783             :   // read input files
     784           1 :   void read_inputfiles(const std::vector<std::string>& input_filename)
     785             :   {
     786             :     char sharp;
     787             :     double nothing;
     788             :     int dimension_temp;
     789             : 
     790           1 :     std::vector<double> loop_bin_size(dimension, 0);
     791           1 :     std::vector<double> position_temp(dimension, 0);
     792           1 :     std::vector<double> grad_temp(dimension, 0);
     793           1 :     int count_temp = 0;
     794           5 :     for (unsigned int i = 0; i < input_filename.size(); i++)
     795             :     {
     796           1 :       int size = 1, size_temp = 0;
     797             : 
     798           1 :       std::string count_filename = input_filename[i] + ".UI.count";
     799           1 :       std::string grad_filename = input_filename[i] + ".UI.grad";
     800             : 
     801           2 :       std::ifstream count_file(count_filename.c_str(), std::ios::in);
     802           2 :       std::ifstream grad_file(grad_filename.c_str(), std::ios::in);
     803             : 
     804           1 :       count_file >> sharp >> dimension_temp;
     805           1 :       grad_file >> sharp >> dimension_temp;
     806             : 
     807           5 :       for (int j = 0; j < dimension; j++)
     808             :       {
     809           4 :         count_file >> sharp >> nothing >> nothing >> size_temp >> nothing;
     810           2 :         grad_file >> sharp >> nothing >> nothing >> nothing >> nothing;
     811           2 :         size *= size_temp;
     812             :       }
     813             : 
     814          19 :       for (int j = 0; j < size; j++)
     815             :       {
     816             :         do
     817             :         {
     818          45 :           for (int k = 0; k < dimension; k++)
     819             :           {
     820          18 :             count_file >> position_temp[k];
     821             :             grad_file >> nothing;
     822             :           }
     823             : 
     824          45 :           for (int l = 0; l < dimension; l++)
     825             :           {
     826          18 :             grad_file >> grad_temp[l];
     827             :           }
     828           9 :           count_file >> count_temp;
     829             :         }
     830          27 :         while (position_temp[i] < lowerboundary[i] - 0.000001 || position_temp[i] > upperboundary[i] + 0.000001);
     831             : 
     832           9 :         if (count_temp == 0)
     833             :         {
     834           5 :           continue;
     835             :         }
     836             : 
     837          20 :         for (int m = 0; m < dimension; m++)
     838             :         {
     839          56 :           grad_temp[m] = (grad_temp[m] * count_temp + input_grad.get_value(position_temp)[m] * input_count.get_value(position_temp)) / (count_temp + input_count.get_value(position_temp));
     840             :         }
     841           4 :         input_grad.set_value(position_temp, grad_temp);
     842           4 :         input_count.increase_value(position_temp, count_temp);
     843             :       }
     844             : 
     845           1 :       count_file.close();
     846           1 :       grad_file.close();
     847             :     }
     848           1 :   }
     849             : };
     850             : }
     851             : 
     852             : }
     853             : }
     854             : 
     855             : #endif

Generated by: LCOV version 1.13