LCOV - code coverage report
Current view: top level - core - FlexibleBin.cpp (source / functions) Hit Total Coverage
Test: plumed test coverage Lines: 80 101 79.2 %
Date: 2018-12-19 07:49:13 Functions: 5 6 83.3 %

          Line data    Source code
       1             : /* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
       2             :    Copyright (c) 2012-2018 The plumed team
       3             :    (see the PEOPLE file at the root of the distribution for a list of names)
       4             : 
       5             :    See http://www.plumed.org for more information.
       6             : 
       7             :    This file is part of plumed, version 2.
       8             : 
       9             :    plumed 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             :    plumed 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 plumed.  If not, see <http://www.gnu.org/licenses/>.
      21             : +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */
      22             : #include "FlexibleBin.h"
      23             : #include "ActionWithArguments.h"
      24             : #include <cmath>
      25             : #include <iostream>
      26             : #include <vector>
      27             : #include "tools/Matrix.h"
      28             : 
      29             : using namespace std;
      30             : namespace PLMD {
      31             : 
      32             : 
      33          21 : FlexibleBin::FlexibleBin(int type, ActionWithArguments *paction,  double const &d, vector<double> &smin, vector<double> &smax):type(type),paction(paction),sigma(d),sigmamin(smin),sigmamax(smax) {
      34             :   // initialize the averages and the variance matrices
      35          21 :   if(type==diffusion) {
      36           2 :     unsigned ncv=paction->getNumberOfArguments();
      37           2 :     vector<double> average(ncv*(ncv+1)/2);
      38           2 :     vector<double> variance(ncv*(ncv+1)/2);
      39             :   }
      40          21 :   paction->log<<"  Limits for sigmas using adaptive hills:  \n";
      41          61 :   for(unsigned i=0; i<paction->getNumberOfArguments(); ++i) {
      42          40 :     paction->log<<"   CV  "<<paction->getPntrToArgument(i)->getName()<<":\n";
      43          40 :     if(sigmamin[i]>0.) {
      44           0 :       limitmin.push_back(true);
      45           0 :       paction->log<<"       Min "<<sigmamin[i];
      46           0 :       sigmamin[i]*=sigmamin[i]; // this is because the matrix which is calculated is the sigmasquared
      47             :     } else {
      48          40 :       limitmin.push_back(false);
      49          40 :       paction->log<<"       Min No ";
      50             :     }
      51          40 :     if(sigmamax[i]>0.) {
      52           0 :       limitmax.push_back(true);
      53           0 :       paction->log<<"       Max "<<sigmamax[i];
      54           0 :       sigmamax[i]*=sigmamax[i];
      55             :     } else {
      56          40 :       limitmax.push_back(false);
      57          40 :       paction->log<<"       Max No ";
      58             :     }
      59          40 :     paction->log<<" \n";
      60             :   }
      61             : 
      62          21 : }
      63             : /// Update the flexible bin
      64             : /// in case of diffusion based: update at every step
      65             : /// in case of gradient based: update only when you add the hill
      66         778 : void FlexibleBin::update(bool nowAddAHill) {
      67         778 :   unsigned ncv=paction->getNumberOfArguments();
      68         778 :   unsigned dimension=ncv*(ncv+1)/2;
      69             :   // this is done all the times from scratch. It is not an accumulator
      70         778 :   unsigned  k=0;
      71             :   unsigned i;
      72         778 :   vector<double> cv;
      73        1556 :   vector<double> delta;
      74             :   // if you use this below then the decay is in time units
      75             :   //double decay=paction->getTimeStep()/sigma;
      76             :   // to be consistent with the rest of the program: everything is better to be in timesteps
      77         778 :   double decay=1./sigma;
      78             :   // here update the flexible bin according to the needs
      79         778 :   switch (type) {
      80             :   // This should be called every time
      81             :   case diffusion:
      82             :     //
      83             :     // THE AVERAGE VALUE
      84             :     //
      85             :     // beware: the pbc
      86         586 :     delta.resize(ncv);
      87         586 :     for(i=0; i<ncv; i++)cv.push_back(paction->getArgument(i));
      88         586 :     if(average.size()==0) { // initial time: just set the initial vector
      89           2 :       average.resize(ncv);
      90           2 :       for(i=0; i<ncv; i++)average[i]=cv[i];
      91             :     } else { // accumulate
      92        1168 :       for(i=0; i<ncv; i++) {
      93         584 :         delta[i]=paction->difference(i,average[i],cv[i]);
      94         584 :         average[i]+=decay*delta[i];
      95         584 :         average[i]=paction->bringBackInPbc(i,average[i]); // equation 8 of "Metadynamics with adaptive Gaussians"
      96             :       }
      97             : 
      98             :     }
      99             :     //
     100             :     // THE VARIANCE
     101             :     //
     102         586 :     if(variance.size()==0) {
     103           2 :       variance.resize(dimension,0.); // nonredundant members dimension=ncv*(ncv+1)/2;
     104             :     } else {
     105         584 :       k=0;
     106        1168 :       for(i=0; i<ncv; i++) {
     107        1168 :         for(unsigned j=i; j<ncv; j++) { // upper diagonal loop
     108         584 :           variance[k]+=decay*(delta[i]*delta[j]-variance[k]);
     109         584 :           k++;
     110             :         }
     111             :       }
     112             :     }
     113         586 :     break;
     114             :   case geometry:
     115             :     //
     116             :     //this calculates in variance the \nabla CV_i \dot \nabla CV_j
     117             :     //
     118         192 :     variance.resize(dimension);
     119             :     //cerr<< "Doing geometry "<<endl;
     120             :     // now the signal for retrieving the gradients should be already given by checkNeedsGradients.
     121             :     // here just do the projections
     122             :     // note that the call  checkNeedsGradients() in BiasMetaD takes care of switching on the call to gradients
     123         192 :     if (nowAddAHill) { // geometry is sync with hill deposition
     124             :       //cerr<< "add a hill "<<endl;
     125          83 :       k=0;
     126         249 :       for(unsigned i=0; i<ncv; i++) {
     127         415 :         for(unsigned j=i; j<ncv; j++) {
     128             :           // eq 12 of "Metadynamics with adaptive Gaussians"
     129         249 :           variance[k]=sigma*sigma*(paction->getProjection(i,j));
     130         249 :           k++;
     131             :         }
     132             :       };
     133             :     };
     134         192 :     break;
     135             :   default:
     136           0 :     cerr<< "This flexible bin is not recognized  "<<endl;
     137           0 :     exit(1)     ;
     138         778 :   }
     139             : 
     140         778 : }
     141             : 
     142           0 : vector<double> FlexibleBin::getMatrix() const {
     143           0 :   return variance;
     144             : }
     145             : 
     146             : ///
     147             : /// Calculate the matrix of  (dcv_i/dx)*(dcv_j/dx)^-1
     148             : /// that is needed for the metrics in metadynamics
     149             : ///
     150             : ///
     151         374 : vector<double> FlexibleBin::getInverseMatrix() const {
     152         374 :   unsigned ncv=paction->getNumberOfArguments();
     153         374 :   Matrix<double> matrix(ncv,ncv);
     154             :   unsigned i,j,k;
     155         374 :   k=0;
     156             :   //paction->log<<"------------ GET INVERSE MATRIX ---------------\n";
     157             :   // place the matrix in a complete matrix for compatibility
     158         831 :   for (i=0; i<ncv; i++) {
     159         997 :     for (j=i; j<ncv; j++) {
     160         540 :       matrix(j,i)=matrix(i,j)=variance[k];
     161         540 :       k++;
     162             :     }
     163             :   }
     164             : //      paction->log<<"MATRIX\n";
     165             : //      matrixOut(paction->log,matrix);
     166             : #define NEWFLEX
     167             : #ifdef NEWFLEX
     168             :   // diagonalize to impose boundaries (only if boundaries are set)
     169         748 :   Matrix<double> eigenvecs(ncv,ncv);
     170         748 :   vector<double> eigenvals(ncv);
     171             : 
     172             :   //eigenvecs: first is eigenvec number, second is eigenvec component
     173         374 :   if(diagMat( matrix, eigenvals, eigenvecs )!=0) {plumed_merror("diagonalization in FlexibleBin failed! This matrix is weird\n");};
     174             : 
     175             : //      paction->log<<"EIGENVECS \n";
     176             : //      matrixOut(paction->log,eigenvecs);
     177             : 
     178             :   //for (i=0;i<ncv;i++){//loop on the dimension
     179             :   //    for (j=0;j<ncv;j++){//loop on the dimension
     180             :   //    eigenvecs[i][j]=0.;
     181             :   //    if(i==j)eigenvecs[i][j]=1.;
     182             :   //    }
     183             :   //}
     184             : 
     185         831 :   for (i=0; i<ncv; i++) { //loop on the dimension
     186         457 :     if( limitmax[i] ) {
     187             :       //limit every  component that is larger
     188           0 :       for (j=0; j<ncv; j++) { //loop on components
     189           0 :         if(pow(eigenvals[j]*eigenvecs[j][i],2)>pow(sigmamax[i],2) ) {
     190           0 :           eigenvals[j]=sqrt(pow(sigmamax[i]/(eigenvecs[j][i]),2))*copysign(1.,eigenvals[j]);
     191             :         }
     192             :       }
     193             :     }
     194             :   }
     195         831 :   for (i=0; i<ncv; i++) { //loop on the dimension
     196             :     // find the largest one:  if it is smaller than min  then rescale
     197         457 :     if( limitmin[i] ) {
     198           0 :       unsigned imax=0;
     199           0 :       double fmax=-1.e10;
     200           0 :       for (j=0; j<ncv; j++) { //loop on components
     201           0 :         double fact=pow(eigenvals[j]*eigenvecs[j][i],2);
     202           0 :         if(fact>fmax) {
     203           0 :           fmax=fact; imax=j;
     204             :         }
     205             :       }
     206           0 :       if(fmax<pow(sigmamin[i],2) ) {
     207           0 :         eigenvals[imax]=sqrt(pow(sigmamin[i]/(eigenvecs[imax][i]),2))*copysign(1.,eigenvals[imax]);
     208             :       }
     209             : 
     210             :     }
     211             : 
     212             :   }
     213             : 
     214             :   // normalize eigenvecs
     215         748 :   Matrix<double> newinvmatrix(ncv,ncv);
     216         831 :   for (i=0; i<ncv; i++) {
     217        1080 :     for (j=0; j<ncv; j++) {
     218         623 :       newinvmatrix[j][i]=eigenvecs[j][i]/eigenvals[j];
     219             :     }
     220             :   }
     221             : 
     222         374 :   vector<double> uppervec(ncv*(ncv+1)/2);
     223         374 :   k=0;
     224         831 :   for (i=0; i<ncv; i++) {
     225         997 :     for (j=i; j<ncv; j++) {
     226         540 :       double scal=0;
     227        1329 :       for(unsigned l=0; l<ncv; ++l) {
     228         789 :         scal+=eigenvecs[l][i]*newinvmatrix[l][j];
     229             :       }
     230         540 :       uppervec[k]=scal; k++;
     231             :     }
     232             :   }
     233             : #else
     234             :   // get the inverted matrix
     235             :   Matrix<double> invmatrix(ncv,ncv);
     236             :   Invert(matrix,invmatrix);
     237             :   vector<double> uppervec(ncv*(ncv+1)/2);
     238             :   // upper diagonal of the inverted matrix (that is symmetric)
     239             :   k=0;
     240             :   for (i=0; i<ncv; i++) {
     241             :     for (j=i; j<ncv; j++) {
     242             :       uppervec[k]=invmatrix(i,j);
     243             :       //paction->log<<"VV "<<i<<" "<<j<<" "<<uppervec[k]<<"\n";
     244             :       k++;
     245             :     }
     246             :   }
     247             :   //paction->log<<"------------ END GET INVERSE MATRIX ---------------\n";
     248             : #endif
     249             : 
     250         748 :   return uppervec;
     251             : }
     252             : 
     253        2523 : }

Generated by: LCOV version 1.13