LCOV - code coverage report
Current view: top level - colvar - PathMSDBase.cpp (source / functions) Hit Total Coverage
Test: plumed test coverage Lines: 161 164 98.2 %
Date: 2020-11-18 11:20:57 Functions: 6 9 66.7 %

          Line data    Source code
       1             : /* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
       2             :    Copyright (c) 2012-2019 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 "PathMSDBase.h"
      23             : #include "Colvar.h"
      24             : #include "ActionRegister.h"
      25             : #include "core/PlumedMain.h"
      26             : #include "core/Atoms.h"
      27             : #include "tools/PDB.h"
      28             : #include "tools/RMSD.h"
      29             : #include "tools/Tools.h"
      30             : #include <cmath>
      31             : 
      32             : using namespace std;
      33             : 
      34             : namespace PLMD {
      35             : namespace colvar {
      36             : 
      37          26 : void PathMSDBase::registerKeywords(Keywords& keys) {
      38          26 :   Colvar::registerKeywords(keys);
      39          52 :   keys.remove("NOPBC");
      40         104 :   keys.add("compulsory","LAMBDA","the lambda parameter is needed for smoothing, is in the units of plumed");
      41         104 :   keys.add("compulsory","REFERENCE","the pdb is needed to provide the various milestones");
      42         104 :   keys.add("optional","NEIGH_SIZE","size of the neighbor list");
      43         104 :   keys.add("optional","NEIGH_STRIDE","how often the neighbor list needs to be calculated in time units");
      44         104 :   keys.add("optional", "EPSILON", "(default=-1) the maximum distance between the close and the current structure, the positive value turn on the close structure method");
      45         104 :   keys.add("optional", "LOG-CLOSE", "(default=0) value 1 enables logging regarding the close structure");
      46         104 :   keys.add("optional", "DEBUG-CLOSE", "(default=0) value 1 enables extensive debugging info regarding the close structure, the simulation will run much slower");
      47         104 :   keys.add("optional", "LOG_CLOSE", "same as LOG-CLOSE");
      48         104 :   keys.add("optional", "DEBUG_CLOSE", "same as DEBUG-CLOSE");
      49          26 : }
      50             : 
      51          24 : PathMSDBase::PathMSDBase(const ActionOptions&ao):
      52             :   PLUMED_COLVAR_INIT(ao),
      53             :   neigh_size(-1),
      54             :   neigh_stride(-1),
      55             :   epsilonClose(-1),
      56             :   debugClose(0),
      57             :   logClose(0),
      58             :   computeRefClose(false),
      59         264 :   nframes(0)
      60             : {
      61          48 :   parse("LAMBDA",lambda);
      62          48 :   parse("NEIGH_SIZE",neigh_size);
      63          48 :   parse("NEIGH_STRIDE",neigh_stride);
      64          48 :   parse("REFERENCE",reference);
      65          48 :   parse("EPSILON", epsilonClose);
      66          48 :   parse("LOG-CLOSE", logClose);
      67          47 :   if(!logClose) parse("LOG_CLOSE", logClose);
      68          48 :   parse("DEBUG-CLOSE", debugClose);
      69          47 :   if(!debugClose) parse("DEBUG_CLOSE",debugClose);
      70             : 
      71             :   // open the file
      72          48 :   FILE* fp=fopen(reference.c_str(),"r");
      73             :   std::vector<AtomNumber> aaa;
      74          24 :   if (fp!=NULL)
      75             :   {
      76          48 :     log<<"Opening reference file "<<reference.c_str()<<"\n";
      77             :     bool do_read=true;
      78        1056 :     while (do_read) {
      79        2088 :       PDB mypdb;
      80        2088 :       RMSD mymsd;
      81        2112 :       do_read=mypdb.readFromFilepointer(fp,plumed.getAtoms().usingNaturalUnits(),0.1/atoms.getUnits().getLength());
      82        1056 :       if(do_read) {
      83        1032 :         nframes++;
      84        2064 :         if(mypdb.getAtomNumbers().size()==0) error("number of atoms in a frame should be more than zero");
      85        1032 :         unsigned nat=mypdb.getAtomNumbers().size();
      86        2064 :         if(nat!=mypdb.getAtomNumbers().size()) error("frames should have the same number of atoms");
      87        1032 :         if(aaa.empty()) aaa=mypdb.getAtomNumbers();
      88        2064 :         if(aaa!=mypdb.getAtomNumbers()) error("frames should contain same atoms in same order");
      89        2064 :         log<<"Found PDB: "<<nframes<<" containing  "<<mypdb.getAtomNumbers().size()<<" atoms\n";
      90        1032 :         pdbv.push_back(mypdb);
      91        2064 :         derivs_s.resize(mypdb.getAtomNumbers().size());
      92        2064 :         derivs_z.resize(mypdb.getAtomNumbers().size());
      93        2064 :         mymsd.set(mypdb,"OPTIMAL");
      94        1032 :         msdv.push_back(mymsd); // the vector that stores the frames
      95             :       } else {break ;}
      96             :     }
      97          24 :     fclose (fp);
      98          48 :     log<<"Found TOTAL "<<nframes<< " PDB in the file "<<reference.c_str()<<" \n";
      99          24 :     if(nframes==0) error("at least one frame expected");
     100             :     //set up rmsdRefClose, initialize it to the first structure loaded from reference file
     101          72 :     rmsdPosClose.set(pdbv[0], "OPTIMAL");
     102          24 :     firstPosClose = true;
     103             :   }
     104          24 :   if(neigh_stride>0 || neigh_size>0) {
     105          14 :     if(neigh_size>int(nframes)) {
     106           0 :       log.printf(" List size required ( %d ) is too large: resizing to the maximum number of frames required: %u  \n",neigh_size,nframes);
     107           0 :       neigh_size=nframes;
     108             :     }
     109          14 :     log.printf("  Neighbor list enabled: \n");
     110          14 :     log.printf("                size   :  %d elements\n",neigh_size);
     111          14 :     log.printf("                stride :  %d timesteps \n",neigh_stride);
     112             :   } else {
     113          10 :     log.printf("  Neighbor list NOT enabled \n");
     114             :   }
     115          24 :   if (epsilonClose > 0) {
     116           2 :     log.printf(" Computing with the close structure, epsilon = %lf\n", epsilonClose);
     117           6 :     log << "  Bibliography " << plumed.cite("Pazurikova J, Krenek A, Spiwok V, Simkova M J. Chem. Phys. 146, 115101 (2017)") << "\n";
     118             :   }
     119             :   else {
     120          22 :     debugClose = 0;
     121          22 :     logClose = 0;
     122             :   }
     123          24 :   if (debugClose)
     124           2 :     log.printf(" Extensive debug info regarding close structure turned on\n");
     125             : 
     126          24 :   rotationRefClose.resize(nframes);
     127          48 :   savedIndices = vector<unsigned>(nframes);
     128             : 
     129          24 : }
     130             : 
     131          72 : PathMSDBase::~PathMSDBase() {
     132          24 : }
     133             : 
     134       11128 : void PathMSDBase::calculate() {
     135             : 
     136       11128 :   if(neigh_size>0 && getExchangeStep()) error("Neighbor lists for this collective variable are not compatible with replica exchange, sorry for that!");
     137             : 
     138             :   //log.printf("NOW CALCULATE! \n");
     139             : 
     140             : 
     141             :   // resize the list to full
     142       11128 :   if(imgVec.empty()) { // this is the signal that means: recalculate all
     143        7163 :     imgVec.resize(nframes);
     144             :     #pragma omp simd
     145        7163 :     for(unsigned i=0; i<nframes; i++) {
     146      601740 :       imgVec[i].property=indexvec[i];
     147      300870 :       imgVec[i].index=i;
     148             :     }
     149             :   }
     150             : 
     151             : // THIS IS THE HEAVY PART (RMSD STUFF)
     152       11128 :   unsigned stride=comm.Get_size();
     153       11128 :   unsigned rank=comm.Get_rank();
     154       11128 :   unsigned nat=pdbv[0].size();
     155       11128 :   plumed_assert(nat>0);
     156       11128 :   plumed_assert(nframes>0);
     157       11128 :   plumed_assert(imgVec.size()>0);
     158             : 
     159       11128 :   std::vector<Tensor> tmp_rotationRefClose(nframes);
     160             : 
     161       11128 :   if (epsilonClose > 0) {
     162             :     //compute rmsd between positions and close structure, save rotation matrix, drotation_drr01
     163        2184 :     double posclose = rmsdPosClose.calc_Rot_DRotDRr01(getPositions(), rotationPosClose, drotationPosCloseDrr01, true);
     164             :     //if we compute for the first time or the existing close structure is too far from current structure
     165        1092 :     if (firstPosClose || (posclose > epsilonClose)) {
     166             :       //set the current structure as close one for a few next steps
     167          16 :       if (logClose)
     168          16 :         log << "PLUMED-CLOSE: new close structure, rmsd pos close " << posclose << "\n";
     169          16 :       rmsdPosClose.clear();
     170          16 :       rmsdPosClose.setReference(getPositions());
     171             :       //as this is a new close structure, we need to save the rotation matrices fitted to the reference structures
     172             :       // and we need to accurately recalculate for all reference structures
     173          16 :       computeRefClose = true;
     174          16 :       imgVec.resize(nframes);
     175        1360 :       for(unsigned i=0; i<nframes; i++) {
     176        1344 :         imgVec[i].property=indexvec[i];
     177         672 :         imgVec[i].index=i;
     178             :       }
     179          16 :       firstPosClose = false;
     180             :     }
     181             :     else {
     182             :       //the current structure is pretty close to the close structure, so we use saved rotation matrices to decrease the complexity of rmsd comuptation
     183        1076 :       if (debugClose)
     184        1076 :         log << "PLUMED-CLOSE: old close structure, rmsd pos close " << posclose << "\n";
     185        1076 :       computeRefClose = false;
     186             :     }
     187             :   }
     188             : 
     189       22256 :   std::vector<double> tmp_distances(imgVec.size(),0.0);
     190             :   std::vector<Vector> tmp_derivs;
     191             : // this array is a merge of all tmp_derivs, so as to allow a single comm.Sum below
     192       11128 :   std::vector<Vector> tmp_derivs2(imgVec.size()*nat);
     193             : 
     194             : // if imgVec.size() is less than nframes, it means that only some msd will be calculated
     195       11128 :   if (epsilonClose > 0) {
     196        1092 :     if (computeRefClose) {
     197             :       //recompute rotation matrices accurately
     198        2048 :       for(unsigned i=rank; i<imgVec.size(); i+=stride) {
     199        1344 :         tmp_distances[i] = msdv[imgVec[i].index].calc_Rot(getPositions(), tmp_derivs, tmp_rotationRefClose[imgVec[i].index], true);
     200         672 :         plumed_assert(tmp_derivs.size()==nat);
     201             :         #pragma omp simd
     202       26208 :         for(unsigned j=0; j<nat; j++) tmp_derivs2[i*nat+j]=tmp_derivs[j];
     203             :       }
     204             :     }
     205             :     else {
     206             :       //approximate distance with saved rotation matrices
     207      137728 :       for(unsigned i=rank; i<imgVec.size(); i+=stride) {
     208      180768 :         tmp_distances[i] = msdv[imgVec[i].index].calculateWithCloseStructure(getPositions(), tmp_derivs, rotationPosClose, rotationRefClose[imgVec[i].index], drotationPosCloseDrr01, true);
     209       45192 :         plumed_assert(tmp_derivs.size()==nat);
     210             :         #pragma omp simd
     211     1762488 :         for(unsigned j=0; j<nat; j++) tmp_derivs2[i*nat+j]=tmp_derivs[j];
     212       45192 :         if (debugClose) {
     213       45192 :           double withclose = tmp_distances[i];
     214       90384 :           RMSD opt;
     215       90384 :           opt.setType("OPTIMAL");
     216      135576 :           opt.setReference(msdv[imgVec[i].index].getReference());
     217             :           vector<Vector> ders;
     218       45192 :           double withoutclose = opt.calculate(getPositions(), ders, true);
     219       45192 :           float difference = fabs(withoutclose-withclose);
     220       90384 :           log.printf("PLUMED-CLOSE: difference original %lf - with close %lf = %lf, step %d, i %d imgVec[i].index %d \n", withoutclose, withclose, difference, getStep(), i, imgVec[i].index);
     221             :         }
     222             :       }
     223             :     }
     224             :   }
     225             :   else {
     226             :     // store temporary local results
     227      875504 :     for(unsigned i=rank; i<imgVec.size(); i+=stride) {
     228      570288 :       tmp_distances[i]=msdv[imgVec[i].index].calculate(getPositions(),tmp_derivs,true);
     229      285144 :       plumed_assert(tmp_derivs.size()==nat);
     230             :       #pragma omp simd
     231    11097666 :       for(unsigned j=0; j<nat; j++) tmp_derivs2[i*nat+j]=tmp_derivs[j];
     232             :     }
     233             :   }
     234             : 
     235             : // reduce over all processors
     236       11128 :   comm.Sum(tmp_distances);
     237       11128 :   comm.Sum(tmp_derivs2);
     238       11128 :   if (epsilonClose > 0 && computeRefClose) {
     239          16 :     comm.Sum(tmp_rotationRefClose);
     240        1360 :     for (unsigned i=0; i<nframes; i++) {
     241        1344 :       rotationRefClose[i] = tmp_rotationRefClose[i];
     242             :     }
     243             :   }
     244             : // assign imgVec[i].distance and imgVec[i].distder
     245     1428056 :   for(unsigned i=0; i<imgVec.size(); i++) {
     246      468600 :     imgVec[i].distance=tmp_distances[i];
     247      937200 :     imgVec[i].distder.assign(&tmp_derivs2[i*nat],nat+&tmp_derivs2[i*nat]);
     248             :   }
     249             : 
     250             : // END OF THE HEAVY PART
     251             : 
     252             :   vector<Value*> val_s_path;
     253       11128 :   if(labels.size()>0) {
     254       72072 :     for(unsigned i=0; i<labels.size(); i++) { val_s_path.push_back(getPntrToComponent(labels[i].c_str()));}
     255             :   } else {
     256       15366 :     val_s_path.push_back(getPntrToComponent("sss"));
     257             :   }
     258       22256 :   Value* val_z_path=getPntrToComponent("zzz");
     259             : 
     260       56524 :   vector<double> s_path(val_s_path.size()); for(unsigned i=0; i<s_path.size(); i++)s_path[i]=0.;
     261             :   double partition=0.;
     262             :   double tmp;
     263             : 
     264             :   // clean vector
     265      455789 :   for(unsigned i=0; i< derivs_z.size(); i++) {derivs_z[i].zero();}
     266             : 
     267      479728 :   for(auto & it : imgVec) {
     268      468600 :     it.similarity=exp(-lambda*(it.distance));
     269             :     //log<<"DISTANCE "<<(*it).distance<<"\n";
     270     3099756 :     for(unsigned i=0; i<s_path.size(); i++) {
     271     1441704 :       s_path[i]+=(it.property[i])*it.similarity;
     272             :     }
     273      468600 :     partition+=it.similarity;
     274             :   }
     275      125060 :   for(unsigned i=0; i<s_path.size(); i++) { s_path[i]/=partition;  val_s_path[i]->set(s_path[i]) ;}
     276       11128 :   val_z_path->set(-(1./lambda)*std::log(partition));
     277       73658 :   for(unsigned j=0; j<s_path.size(); j++) {
     278             :     // clean up
     279             :     #pragma omp simd
     280      239723 :     for(unsigned i=0; i< derivs_s.size(); i++) {derivs_s[i].zero();}
     281             :     // do the derivative
     282      737986 :     for(const auto & it : imgVec) {
     283      720852 :       double expval=it.similarity;
     284     2162556 :       tmp=lambda*expval*(s_path[j]-it.property[j])/partition;
     285             :       #pragma omp simd
     286    19447704 :       for(unsigned i=0; i< derivs_s.size(); i++) { derivs_s[i]+=tmp*it.distder[i] ;}
     287      720852 :       if(j==0) {
     288             :         #pragma omp simd
     289    12636900 :         for(unsigned i=0; i< derivs_z.size(); i++) { derivs_z[i]+=it.distder[i]*expval/partition;}
     290             :       }
     291             :     }
     292      702035 :     for(unsigned i=0; i< derivs_s.size(); i++) {
     293      667767 :       setAtomsDerivatives (val_s_path[j],i,derivs_s[i]);
     294      367100 :       if(j==0) {setAtomsDerivatives (val_z_path,i,derivs_z[i]);}
     295             :     }
     296             :   }
     297       73658 :   for(unsigned i=0; i<val_s_path.size(); ++i) setBoxDerivativesNoPbc(val_s_path[i]);
     298       11128 :   setBoxDerivativesNoPbc(val_z_path);
     299             :   //
     300             :   //  here set next round neighbors
     301             :   //
     302       11128 :   if (neigh_size>0) {
     303             :     //if( int(getStep())%int(neigh_stride/getTimeStep())==0 ){
     304             :     // enforce consistency: the stride is in time steps
     305        7153 :     if( int(getStep())%int(neigh_stride)==0 ) {
     306             : 
     307             :       // next round do it all:empty the vector
     308             :       imgVec.clear();
     309             :     }
     310             :     // time to analyze the results:
     311        7153 :     if(imgVec.size()==nframes) {
     312             :       //sort by msd
     313             :       sort(imgVec.begin(), imgVec.end(), imgOrderByDist());
     314             :       //resize
     315           0 :       imgVec.resize(neigh_size);
     316             :     }
     317             :   }
     318             :   //log.printf("CALCULATION DONE! \n");
     319       11128 : }
     320             : 
     321             : }
     322             : 
     323        4839 : }

Generated by: LCOV version 1.13