LCOV - code coverage report
Current view: top level - colvar - PCARMSD.cpp (source / functions) Hit Total Coverage
Test: plumed test coverage Lines: 109 110 99.1 %
Date: 2019-08-13 10:39:37 Functions: 10 12 83.3 %

          Line data    Source code
       1             : /* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
       2             :    Copyright (c) 2014-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 "Colvar.h"
      23             : #include "core/Atoms.h"
      24             : #include "core/PlumedMain.h"
      25             : #include "ActionRegister.h"
      26             : #include "tools/PDB.h"
      27             : #include "tools/RMSD.h"
      28             : #include "tools/Tools.h"
      29             : 
      30             : using namespace std;
      31             : 
      32             : namespace PLMD {
      33             : namespace colvar {
      34             : 
      35             : class PCARMSD : public Colvar {
      36             : 
      37             :   PLMD::RMSD* rmsd;
      38             :   bool squared;
      39             :   std::vector< std::vector<Vector> > eigenvectors;
      40             :   std::vector<PDB> pdbv;
      41             :   std::vector<string> pca_names;
      42             : public:
      43             :   explicit PCARMSD(const ActionOptions&);
      44             :   ~PCARMSD();
      45             :   virtual void calculate();
      46             :   static void registerKeywords(Keywords& keys);
      47             : };
      48             : 
      49             : 
      50             : using namespace std;
      51             : 
      52             : //+PLUMEDOC DCOLVAR PCARMSD
      53             : /*
      54             : Calculate the PCA components ( see \cite Sutto:2010 and \cite spiwok )  for a number of provided eigenvectors and an average structure. Performs optimal alignment at every step and reports the rmsd so you know if you are far or close from the average structure.
      55             : It takes the average structure and eigenvectors in form of a pdb.
      56             : Note that beta and occupancy values in the pdb are neglected and all the weights are placed to 1 (differently from the RMSD colvar for example)
      57             : 
      58             : \par Examples
      59             : 
      60             : \plumedfile
      61             : PCARMSD AVERAGE=file.pdb EIGENVECTORS=eigenvectors.pdb
      62             : \endplumedfile
      63             : 
      64             : The input is taken so to be compatible with the output you get from g_covar utility of gromacs (suitably adapted to have a pdb input format).
      65             : 
      66             : */
      67             : //+ENDPLUMEDOC
      68             : 
      69        4822 : PLUMED_REGISTER_ACTION(PCARMSD,"PCARMSD")
      70             : 
      71           2 : void PCARMSD::registerKeywords(Keywords& keys) {
      72           2 :   Colvar::registerKeywords(keys);
      73           2 :   keys.add("compulsory","AVERAGE","a file in pdb format containing the reference structure and the atoms involved in the CV.");
      74           2 :   keys.add("compulsory","EIGENVECTORS","a file in pdb format containing the reference structure and the atoms involved in the CV.");
      75             :   //useCustomisableComponents(keys);
      76           2 :   keys.addOutputComponent("eig","default","the projections on each eigenvalue are stored on values labeled eig-1, eig-2, ...");
      77           2 :   keys.addOutputComponent("residual","default","the distance of the present configuration from the configuration supplied as AVERAGE in terms of MSD after optimal alignment ");
      78           2 :   keys.addFlag("SQUARED-ROOT",false," This should be setted if you want RMSD instead of MSD ");
      79           2 :   keys.addFlag("SQUARED_ROOT",false," Same as SQUARED-ROOT");
      80           2 : }
      81             : 
      82           1 : PCARMSD::PCARMSD(const ActionOptions&ao):
      83           1 :   PLUMED_COLVAR_INIT(ao),squared(true)
      84             : {
      85           1 :   string f_average;
      86           1 :   parse("AVERAGE",f_average);
      87           2 :   string type;
      88           1 :   type.assign("OPTIMAL");
      89           2 :   string f_eigenvectors;
      90           1 :   parse("EIGENVECTORS",f_eigenvectors);
      91           1 :   bool sq;  parseFlag("SQUARED-ROOT",sq);
      92           1 :   if(!sq) parseFlag("SQUARED_ROOT",sq);
      93           1 :   if (sq) { squared=false; }
      94           1 :   checkRead();
      95             : 
      96           2 :   PDB pdb;
      97             : 
      98             :   // read everything in ang and transform to nm if we are not in natural units
      99           1 :   if( !pdb.read(f_average,plumed.getAtoms().usingNaturalUnits(),0.1/atoms.getUnits().getLength()) )
     100           0 :     error("missing input file " + f_average );
     101             : 
     102           1 :   rmsd = new RMSD();
     103           1 :   bool remove_com=true;
     104           1 :   bool normalize_weights=true;
     105             :   // here align and displace are a simple vector of ones
     106           2 :   std::vector<double> align; align=pdb.getOccupancy(); for(unsigned i=0; i<align.size(); i++) {align[i]=1.;} ;
     107           2 :   std::vector<double> displace;  displace=pdb.getBeta(); for(unsigned i=0; i<displace.size(); i++) {displace[i]=1.;} ;
     108             :   // reset again to reimpose unifrom weights (safe to disable this)
     109           1 :   rmsd->set(align,displace,pdb.getPositions(),type,remove_com,normalize_weights);
     110           1 :   requestAtoms( pdb.getAtomNumbers() );
     111             : 
     112           1 :   addComponentWithDerivatives("residual"); componentIsNotPeriodic("residual");
     113             : 
     114           1 :   log.printf("  average from file %s\n",f_average.c_str());
     115           1 :   log.printf("  which contains %d atoms\n",getNumberOfAtoms());
     116           1 :   log.printf("  method for alignment : %s \n",type.c_str() );
     117             : 
     118           1 :   log<<"  Bibliography "<<plumed.cite("Spiwok, Lipovova and Kralova, JPCB, 111, 3073 (2007)  ");
     119           1 :   log<<" "<<plumed.cite( "Sutto, D'Abramo, Gervasio, JCTC, 6, 3640 (2010)");
     120             : 
     121             :   // now get the eigenvectors
     122             :   // open the file
     123           1 :   FILE* fp=fopen(f_eigenvectors.c_str(),"r");
     124           2 :   std::vector<AtomNumber> aaa;
     125             :   unsigned neigenvects;
     126           1 :   neigenvects=0;
     127           1 :   if (fp!=NULL)
     128             :   {
     129           1 :     log<<"  Opening the eigenvectors file "<<f_eigenvectors.c_str()<<"\n";
     130           1 :     bool do_read=true;
     131          37 :     while (do_read) {
     132          36 :       PDB mypdb;
     133             :       // check the units for reading this file: how can they make sense?
     134          36 :       do_read=mypdb.readFromFilepointer(fp,plumed.getAtoms().usingNaturalUnits(),0.1/atoms.getUnits().getLength());
     135          36 :       if(do_read) {
     136          35 :         neigenvects++;
     137          35 :         if(mypdb.getAtomNumbers().size()==0) error("number of atoms in a frame should be more than zero");
     138          35 :         unsigned nat=mypdb.getAtomNumbers().size();
     139          35 :         if(nat!=mypdb.getAtomNumbers().size()) error("frames should have the same number of atoms");
     140          35 :         if(aaa.empty()) aaa=mypdb.getAtomNumbers();
     141          35 :         if(aaa!=mypdb.getAtomNumbers()) error("frames should contain same atoms in same order");
     142          35 :         log<<"  Found eigenvector: "<<neigenvects<<" containing  "<<mypdb.getAtomNumbers().size()<<" atoms\n";
     143          35 :         pdbv.push_back(mypdb);
     144          35 :         eigenvectors.push_back(mypdb.getPositions());
     145           1 :       } else {break ;}
     146          35 :     }
     147           1 :     fclose (fp);
     148           1 :     log<<"  Found total "<<neigenvects<< " eigenvectors in the file "<<f_eigenvectors.c_str()<<" \n";
     149           1 :     if(neigenvects==0) error("at least one eigenvector is expected");
     150             :   }
     151             :   // the components
     152          36 :   for(unsigned i=0; i<neigenvects; i++) {
     153          35 :     std::string num; Tools::convert( i, num );
     154          70 :     string name; name=string("eig-")+num;
     155          35 :     pca_names.push_back(name);
     156          35 :     addComponentWithDerivatives(name); componentIsNotPeriodic(name);
     157          35 :   }
     158           2 :   turnOnDerivatives();
     159             : 
     160           1 : }
     161             : 
     162           4 : PCARMSD::~PCARMSD() {
     163           1 :   delete rmsd;
     164           3 : }
     165             : 
     166             : 
     167             : // calculator
     168         546 : void PCARMSD::calculate() {
     169         546 :   Tensor rotation,invrotation;
     170         546 :   Matrix<std::vector<Vector> > drotdpos(3,3);
     171        1092 :   std::vector<Vector> alignedpos;
     172        1092 :   std::vector<Vector> centeredpos;
     173        1092 :   std::vector<Vector> centeredref;
     174        1092 :   std::vector<Vector> ddistdpos;
     175         546 :   double r=rmsd->calc_PCAelements( getPositions(), ddistdpos, rotation,  drotdpos, alignedpos,centeredpos, centeredref,squared);
     176         546 :   invrotation=rotation.transpose();
     177             : 
     178         546 :   Value* verr=getPntrToComponent("residual");
     179         546 :   verr->set(r);
     180        6552 :   for(unsigned iat=0; iat<getNumberOfAtoms(); iat++) {
     181        6006 :     setAtomsDerivatives (verr,iat,ddistdpos[iat]);
     182             :   }
     183             : 
     184        1092 :   std::vector< Vector > der;
     185         546 :   der.resize(getNumberOfAtoms());
     186             : 
     187             : 
     188       19656 :   for(unsigned i=0; i<eigenvectors.size(); i++) {
     189       19110 :     Value* value=getPntrToComponent(pca_names[i].c_str());
     190       19110 :     double val; val=0.;
     191      229320 :     for(unsigned iat=0; iat<getNumberOfAtoms(); iat++) {
     192      210210 :       val+=dotProduct(alignedpos[iat]-centeredref[iat],eigenvectors[i][iat]);   der[iat].zero();
     193             :     }
     194       19110 :     value->set(val);
     195             :     // here the loop is reversed to better suit the structure of the derivative of the rotation matrix
     196             :     double tmp1;
     197       76440 :     for(unsigned a=0; a<3; a++) {
     198      229320 :       for(unsigned b=0; b<3; b++) {
     199      171990 :         tmp1=0.;
     200     2063880 :         for(unsigned n=0; n<getNumberOfAtoms(); n++) {
     201     1891890 :           tmp1+=centeredpos[n][b]*eigenvectors[i][n][a];
     202             :         }
     203     2063880 :         for(unsigned iat=0; iat<getNumberOfAtoms(); iat++) {
     204     1891890 :           der[iat]+=drotdpos[a][b][iat]*tmp1;
     205             :         }
     206             :       }
     207             :     }
     208       19110 :     Vector v1;
     209      229320 :     for(unsigned n=0; n<getNumberOfAtoms(); n++) {
     210      210210 :       v1+=(1./getNumberOfAtoms())*matmul(invrotation,eigenvectors[i][n]);
     211             :     }
     212      229320 :     for(unsigned iat=0; iat<getNumberOfAtoms(); iat++) {
     213      210210 :       der[iat]+=matmul(invrotation,eigenvectors[i][iat])-v1;
     214      210210 :       setAtomsDerivatives (value,iat,der[iat]);
     215             :     }
     216             :   }
     217             : 
     218        1092 :   for(int i=0; i<getNumberOfComponents(); ++i) setBoxDerivativesNoPbc( getPntrToComponent(i) );
     219             : 
     220         546 : }
     221             : 
     222             : }
     223        4821 : }
     224             : 
     225             : 
     226             : 

Generated by: LCOV version 1.13