LCOV - code coverage report
Current view: top level - colvar - PCARMSD.cpp (source / functions) Hit Total Coverage
Test: plumed test coverage Lines: 107 108 99.1 %
Date: 2018-12-19 07:49:13 Functions: 10 12 83.3 %

          Line data    Source code
       1             : /* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
       2             :    Copyright (c) 2014-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 "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             : \verbatim
      61             : PCARMSD AVERAGE=file.pdb EIGENVECTORS=eigenvectors.pdb
      62             : \endverbatim
      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        2524 : 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 : }
      80             : 
      81           1 : PCARMSD::PCARMSD(const ActionOptions&ao):
      82           1 :   PLUMED_COLVAR_INIT(ao),squared(true)
      83             : {
      84           1 :   string f_average;
      85           1 :   parse("AVERAGE",f_average);
      86           2 :   string type;
      87           1 :   type.assign("OPTIMAL");
      88           2 :   string f_eigenvectors;
      89           1 :   parse("EIGENVECTORS",f_eigenvectors);
      90           1 :   bool sq;  parseFlag("SQUARED-ROOT",sq);
      91           1 :   if (sq) { squared=false; }
      92           1 :   checkRead();
      93             : 
      94           2 :   PDB pdb;
      95             : 
      96             :   // read everything in ang and transform to nm if we are not in natural units
      97           1 :   if( !pdb.read(f_average,plumed.getAtoms().usingNaturalUnits(),0.1/atoms.getUnits().getLength()) )
      98           0 :     error("missing input file " + f_average );
      99             : 
     100           1 :   rmsd = new RMSD();
     101           1 :   bool remove_com=true;
     102           1 :   bool normalize_weights=true;
     103             :   // here align and displace are a simple vector of ones
     104           2 :   std::vector<double> align; align=pdb.getOccupancy(); for(unsigned i=0; i<align.size(); i++) {align[i]=1.;} ;
     105           2 :   std::vector<double> displace;  displace=pdb.getBeta(); for(unsigned i=0; i<displace.size(); i++) {displace[i]=1.;} ;
     106             :   // reset again to reimpose unifrom weights (safe to disable this)
     107           1 :   rmsd->set(align,displace,pdb.getPositions(),type,remove_com,normalize_weights);
     108           1 :   requestAtoms( pdb.getAtomNumbers() );
     109             : 
     110           1 :   addComponentWithDerivatives("residual"); componentIsNotPeriodic("residual");
     111             : 
     112           1 :   log.printf("  average from file %s\n",f_average.c_str());
     113           1 :   log.printf("  which contains %d atoms\n",getNumberOfAtoms());
     114           1 :   log.printf("  method for alignment : %s \n",type.c_str() );
     115             : 
     116           1 :   log<<"  Bibliography "<<plumed.cite("Spiwok, Lipovova and Kralova, JPCB, 111, 3073 (2007)  ");
     117           1 :   log<<" "<<plumed.cite( "Sutto, D'Abramo, Gervasio, JCTC, 6, 3640 (2010)");
     118             : 
     119             :   // now get the eigenvectors
     120             :   // open the file
     121           1 :   FILE* fp=fopen(f_eigenvectors.c_str(),"r");
     122           2 :   std::vector<AtomNumber> aaa;
     123             :   unsigned neigenvects;
     124           1 :   neigenvects=0;
     125           1 :   if (fp!=NULL)
     126             :   {
     127           1 :     log<<"  Opening the eigenvectors file "<<f_eigenvectors.c_str()<<"\n";
     128           1 :     bool do_read=true;
     129          37 :     while (do_read) {
     130          36 :       PDB mypdb;
     131             :       // check the units for reading this file: how can they make sense?
     132          36 :       do_read=mypdb.readFromFilepointer(fp,plumed.getAtoms().usingNaturalUnits(),0.1/atoms.getUnits().getLength());
     133          36 :       if(do_read) {
     134          35 :         neigenvects++;
     135          35 :         if(mypdb.getAtomNumbers().size()==0) error("number of atoms in a frame should be more than zero");
     136          35 :         unsigned nat=mypdb.getAtomNumbers().size();
     137          35 :         if(nat!=mypdb.getAtomNumbers().size()) error("frames should have the same number of atoms");
     138          35 :         if(aaa.empty()) aaa=mypdb.getAtomNumbers();
     139          35 :         if(aaa!=mypdb.getAtomNumbers()) error("frames should contain same atoms in same order");
     140          35 :         log<<"  Found eigenvector: "<<neigenvects<<" containing  "<<mypdb.getAtomNumbers().size()<<" atoms\n";
     141          35 :         pdbv.push_back(mypdb);
     142          35 :         eigenvectors.push_back(mypdb.getPositions());
     143           1 :       } else {break ;}
     144          35 :     }
     145           1 :     fclose (fp);
     146           1 :     log<<"  Found total "<<neigenvects<< " eigenvectors in the file "<<f_eigenvectors.c_str()<<" \n";
     147           1 :     if(neigenvects==0) error("at least one eigenvector is expected");
     148             :   }
     149             :   // the components
     150          36 :   for(unsigned i=0; i<neigenvects; i++) {
     151          35 :     std::string num; Tools::convert( i, num );
     152          70 :     string name; name=string("eig-")+num;
     153          35 :     pca_names.push_back(name);
     154          35 :     addComponentWithDerivatives(name); componentIsNotPeriodic(name);
     155          35 :   }
     156           2 :   turnOnDerivatives();
     157             : 
     158           1 : }
     159             : 
     160           4 : PCARMSD::~PCARMSD() {
     161           1 :   delete rmsd;
     162           3 : }
     163             : 
     164             : 
     165             : // calculator
     166         546 : void PCARMSD::calculate() {
     167         546 :   Tensor rotation,invrotation;
     168         546 :   Matrix<std::vector<Vector> > drotdpos(3,3);
     169        1092 :   std::vector<Vector> alignedpos;
     170        1092 :   std::vector<Vector> centeredpos;
     171        1092 :   std::vector<Vector> centeredref;
     172        1092 :   std::vector<Vector> ddistdpos;
     173         546 :   double r=rmsd->calc_PCAelements( getPositions(), ddistdpos, rotation,  drotdpos, alignedpos,centeredpos, centeredref,squared);
     174         546 :   invrotation=rotation.transpose();
     175             : 
     176         546 :   Value* verr=getPntrToComponent("residual");
     177         546 :   verr->set(r);
     178        6552 :   for(unsigned iat=0; iat<getNumberOfAtoms(); iat++) {
     179        6006 :     setAtomsDerivatives (verr,iat,ddistdpos[iat]);
     180             :   }
     181             : 
     182        1092 :   std::vector< Vector > der;
     183         546 :   der.resize(getNumberOfAtoms());
     184             : 
     185             : 
     186       19656 :   for(unsigned i=0; i<eigenvectors.size(); i++) {
     187       19110 :     Value* value=getPntrToComponent(pca_names[i].c_str());
     188       19110 :     double val; val=0.;
     189      229320 :     for(unsigned iat=0; iat<getNumberOfAtoms(); iat++) {
     190      210210 :       val+=dotProduct(alignedpos[iat]-centeredref[iat],eigenvectors[i][iat]);   der[iat].zero();
     191             :     }
     192       19110 :     value->set(val);
     193             :     // here the loop is reversed to better suit the structure of the derivative of the rotation matrix
     194             :     double tmp1;
     195       76440 :     for(unsigned a=0; a<3; a++) {
     196      229320 :       for(unsigned b=0; b<3; b++) {
     197      171990 :         tmp1=0.;
     198     2063880 :         for(unsigned n=0; n<getNumberOfAtoms(); n++) {
     199     1891890 :           tmp1+=centeredpos[n][b]*eigenvectors[i][n][a];
     200             :         }
     201     2063880 :         for(unsigned iat=0; iat<getNumberOfAtoms(); iat++) {
     202     1891890 :           der[iat]+=drotdpos[a][b][iat]*tmp1;
     203             :         }
     204             :       }
     205             :     }
     206       19110 :     Vector v1;
     207      229320 :     for(unsigned n=0; n<getNumberOfAtoms(); n++) {
     208      210210 :       v1+=(1./getNumberOfAtoms())*matmul(invrotation,eigenvectors[i][n]);
     209             :     }
     210      229320 :     for(unsigned iat=0; iat<getNumberOfAtoms(); iat++) {
     211      210210 :       der[iat]+=matmul(invrotation,eigenvectors[i][iat])-v1;
     212      210210 :       setAtomsDerivatives (value,iat,der[iat]);
     213             :     }
     214             :   }
     215             : 
     216        1092 :   for(unsigned i=0; i<getNumberOfComponents(); ++i) setBoxDerivativesNoPbc( getPntrToComponent(i) );
     217             : 
     218         546 : }
     219             : 
     220             : }
     221        2523 : }
     222             : 
     223             : 
     224             : 

Generated by: LCOV version 1.13