LCOV - code coverage report
Current view: top level - mapping - AdaptivePath.cpp (source / functions) Hit Total Coverage
Test: plumed test coverage Lines: 94 97 96.9 %
Date: 2025-04-08 21:11:17 Functions: 2 3 66.7 %

          Line data    Source code
       1             : /* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
       2             :    Copyright (c) 2016-2020 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 "core/ActionShortcut.h"
      23             : #include "core/ActionRegister.h"
      24             : #include "core/PlumedMain.h"
      25             : #include "tools/PDB.h"
      26             : #include "Path.h"
      27             : 
      28             : //+PLUMEDOC COLVAR ADAPTIVE_PATH
      29             : /*
      30             : Compute path collective variables that adapt to the lowest free energy path connecting states A and B.
      31             : 
      32             : The Path Collective Variables developed by Branduardi and co-workers \cite brand07 allow one
      33             : to compute the progress along a high-dimensional path and the distance from the high-dimensional
      34             : path.  The progress along the path (s) is computed using:
      35             : 
      36             : \f[
      37             : s = i_2 + \textrm{sign}(i_2-i_1) \frac{ \sqrt{( \mathbf{v}_1\cdot\mathbf{v}_2 )^2 - |\mathbf{v}_3|^2(|\mathbf{v}_1|^2 - |\mathbf{v}_2|^2) } }{2|\mathbf{v}_3|^2} - \frac{\mathbf{v}_1\cdot\mathbf{v}_3 - |\mathbf{v}_3|^2}{2|\mathbf{v}_3|^2}
      38             : \f]
      39             : 
      40             : In this expression \f$\mathbf{v}_1\f$ and \f$\mathbf{v}_3\f$ are the vectors connecting the current position to the closest and second closest node of the path,
      41             : respectfully and \f$i_1\f$ and \f$i_2\f$ are the projections of the closest and second closest frames of the path. \f$\mathbf{v}_2\f$, meanwhile, is the
      42             : vector connecting the closest frame to the second closest frame.  The distance from the path, \f$z\f$ is calculated using:
      43             : 
      44             : \f[
      45             : z = \sqrt{ \left[ |\mathbf{v}_1|^2 - |\mathbf{v}_2| \left( \frac{ \sqrt{( \mathbf{v}_1\cdot\mathbf{v}_2 )^2 - |\mathbf{v}_3|^2(|\mathbf{v}_1|^2 - |\mathbf{v}_2|^2) } }{2|\mathbf{v}_3|^2} - \frac{\mathbf{v}_1\cdot\mathbf{v}_3 - |\mathbf{v}_3|^2}{2|\mathbf{v}_3|^2} \right) \right]^2 }
      46             : \f]
      47             : 
      48             : Notice that these are the definitions of \f$s\f$ and \f$z\f$ that are used by \ref PATH when the GPATH option is employed.  The reason for this is that
      49             : the adaptive path method implemented in this action was inspired by the work of Diaz and Ensing in which these formula were used \cite BerndAdaptivePath.
      50             : To learn more about how the path is adapted we strongly recommend reading this paper.
      51             : 
      52             : \par Examples
      53             : 
      54             : The input below provides an example that shows how the adaptive path works. The path is updated every 50 steps of
      55             : MD based on the data accumulated during the preceding 50 time steps.
      56             : 
      57             : \plumedfile
      58             : d1: DISTANCE ATOMS=1,2 COMPONENTS
      59             : pp: ADAPTIVE_PATH TYPE=EUCLIDEAN FIXED=2,5 UPDATE=50 WFILE=out-path.pdb WSTRIDE=50 REFERENCE=mypath.pdb
      60             : PRINT ARG=d1.x,d1.y,pp.* FILE=colvar
      61             : \endplumedfile
      62             : 
      63             : In the case above the distance between frames is calculated based on the \f$x\f$ and \f$y\f$ components of the vector connecting
      64             : atoms 1 and 2.  As such an extract from the input reference path (mypath.pdb) would look as follows:
      65             : 
      66             : \auxfile{mypath.pdb}
      67             : REMARK ARG=d1.x,d1.y d1.x=1.12 d1.y=-.60
      68             : END
      69             : REMARK ARG=d1.x,d1.y d1.x=.99 d1.y=-.45
      70             : END
      71             : REMARK ARG=d1.x,d1.y d1.x=.86 d1.y=-.30
      72             : END
      73             : REMARK ARG=d1.x,d1.y d1.x=.73 d1.y=-.15
      74             : END
      75             : REMARK ARG=d1.x,d1.y d1.x=.60 d1.y=0
      76             : END
      77             : REMARK ARG=d1.x,d1.y d1.x=.47 d1.y=.15
      78             : END
      79             : \endauxfile
      80             : 
      81             : Notice that one can also use RMSD frames in place of arguments like those above.
      82             : 
      83             : */
      84             : //+ENDPLUMEDOC
      85             : 
      86             : namespace PLMD {
      87             : namespace mapping {
      88             : 
      89             : class AdaptivePath : public ActionShortcut {
      90             : public:
      91             :   static void registerKeywords( Keywords& keys );
      92             :   explicit AdaptivePath(const ActionOptions&);
      93             : };
      94             : 
      95             : PLUMED_REGISTER_ACTION(AdaptivePath,"ADAPTIVE_PATH")
      96             : 
      97           6 : void AdaptivePath::registerKeywords( Keywords& keys ) {
      98           6 :   ActionShortcut::registerKeywords( keys );
      99           6 :   Path::registerInputFileKeywords( keys );
     100           6 :   keys.add("optional","PROPERTY","read in path coordinates by finding option with this label in remark of pdb frames");
     101           6 :   keys.add("compulsory","FIXED","the positions in the list of input frames of the two path nodes whose positions remain fixed during the path optimization");
     102           6 :   keys.add("compulsory","HALFLIFE","-1","the number of MD steps after which a previously measured path distance weighs only 50 percent in the average. This option may increase convergence by allowing to forget the memory of a bad initial guess path. The default is to set this to infinity");
     103           6 :   keys.add("compulsory","UPDATE","the frequency with which the path should be updated");
     104           6 :   keys.add("compulsory","TOLERANCE","1E-6","the tolerance to use for the path updating algorithm that makes all frames equidistant");
     105           6 :   keys.add("optional","WFILE","file on which to write out the path");
     106           6 :   keys.add("compulsory","FMT","%f","the format to use for output files");
     107           6 :   keys.add("compulsory","WSTRIDE","0,","frequency with which to write out the path");
     108          12 :   keys.setValueDescription("scalar","the position along and from the adaptive path");
     109           6 :   keys.needsAction("GEOMETRIC_PATH");
     110           6 :   keys.needsAction("AVERAGE_PATH_DISPLACEMENT");
     111           6 :   keys.needsAction("REPARAMETERIZE_PATH");
     112           6 :   keys.needsAction("DUMPPDB");
     113           6 :   keys.needsAction("PDB2CONSTANT");
     114           6 :   keys.needsAction("DISPLACEMENT");
     115           6 :   keys.needsAction("CONSTANT");
     116           6 : }
     117             : 
     118           2 : AdaptivePath::AdaptivePath(const ActionOptions& ao):
     119             :   Action(ao),
     120           2 :   ActionShortcut(ao) {
     121             :   // Read in the arguments
     122             :   std::vector<std::string> argnames;
     123           4 :   parseVector("ARG",argnames);
     124             :   std::string reference_data, metric, mtype;
     125           4 :   parse("TYPE", mtype);
     126             :   std::string reference;
     127           4 :   parse("REFERENCE",reference);
     128           2 :   FILE* fp=std::fopen(reference.c_str(),"r");
     129           2 :   PDB mypdb;
     130           2 :   if(!fp) {
     131           0 :     error("could not open reference file " + reference );
     132             :   }
     133           2 :   bool do_read=mypdb.readFromFilepointer(fp,false,0.1);
     134           2 :   if( !do_read ) {
     135           0 :     error("missing file " + reference );
     136             :   }
     137             :   // Create list of reference configurations that PLUMED will use
     138           2 :   Path::readInputFrames( reference, mtype, argnames, true, this, reference_data );
     139             :   // Now get coordinates on spath
     140             :   std::vector<std::string> pnames;
     141           2 :   parseVector("PROPERTY",pnames);
     142           2 :   Path::readPropertyInformation( pnames, getShortcutLabel(), reference, this );
     143             :   // Create action that computes the geometric path variablesa
     144           2 :   std::string propstr = getShortcutLabel() + "_ind";
     145           2 :   if( pnames.size()>0 ) {
     146           2 :     propstr = pnames[0] + "_ref";
     147             :   }
     148           2 :   if( argnames.size()>0 ) {
     149           2 :     readInputLine( getShortcutLabel() + ": GEOMETRIC_PATH ARG=" + getShortcutLabel() + "_data " + " PROPERTY=" + propstr + " REFERENCE=" + reference_data + " METRIC={DIFFERENCE}");
     150             :   } else {
     151             :     std::string num, align_str, displace_str;
     152           1 :     Tools::convert( mypdb.getOccupancy()[0], align_str );
     153           1 :     Tools::convert( mypdb.getBeta()[0], displace_str );
     154          13 :     for(unsigned j=1; j<mypdb.getAtomNumbers().size(); ++j ) {
     155          12 :       Tools::convert( mypdb.getOccupancy()[j], num );
     156          12 :       align_str += "," + num;
     157          12 :       Tools::convert( mypdb.getBeta()[0], num );
     158          24 :       displace_str += "," + num;
     159             :     }
     160           2 :     metric = "RMSD_VECTOR DISPLACEMENT TYPE=" + mtype + " ALIGN=" + align_str + " DISPLACE=" + displace_str;
     161           2 :     readInputLine( getShortcutLabel() + ": GEOMETRIC_PATH ARG=" + getShortcutLabel() + "_data.disp " + " PROPERTY=" +  propstr + " REFERENCE=" + reference_data + " METRIC={" + metric + "} METRIC_COMPONENT=disp");
     162             :   }
     163             :   // Create the object to accumulate the average path displacements
     164             :   std::string update, halflife;
     165           2 :   parse("HALFLIFE",halflife);
     166           2 :   parse("UPDATE",update);
     167           4 :   std::string refframes = " REFERENCE=" + getShortcutLabel() + "_pos";
     168           2 :   if( argnames.size()>0 ) {
     169           2 :     readInputLine( getShortcutLabel() + "_disp: AVERAGE_PATH_DISPLACEMENT ARG=" + getShortcutLabel() + "_data HALFLIFE=" + halflife + " CLEAR=" + update + " METRIC={DIFFERENCE} REFERENCE=" + reference_data );
     170             :   } else {
     171           2 :     readInputLine( getShortcutLabel() + "_disp: AVERAGE_PATH_DISPLACEMENT ARG=" + getShortcutLabel() + "_data.disp HALFLIFE=" + halflife + " CLEAR=" + update + " METRIC={" + metric + "} METRIC_COMPONENT=disp REFERENCE=" + reference_data );
     172             :   }
     173             : 
     174             :   // Create the object to update the path
     175             :   std::string fixedn;
     176           2 :   parse("FIXED",fixedn);
     177           2 :   std::string component="METRIC_COMPONENT=disp";
     178           2 :   if( argnames.size()>0 ) {
     179             :     metric="DIFFERENCE";
     180             :     component="";
     181             :   }
     182           4 :   readInputLine("REPARAMETERIZE_PATH DISPLACE_FRAMES=" + getShortcutLabel() + "_disp FIXED=" + fixedn + " STRIDE=" + update + " METRIC={" + metric + "} " + component + " REFERENCE=" + reference_data );
     183             : 
     184             :   // Information for write out
     185             :   std::string wfilename;
     186           4 :   parse("WFILE",wfilename);
     187           2 :   if( wfilename.length()>0 ) {
     188             :     // This just gets the atom numbers for output
     189             :     std::string atomstr;
     190           2 :     if( argnames.size()==0 ) {
     191           1 :       FILE* fp=std::fopen(reference.c_str(),"r");
     192             :       double fake_unit=0.1;
     193           1 :       PDB mypdb;
     194           1 :       bool do_read=mypdb.readFromFilepointer(fp,false,fake_unit);
     195             :       std::string num;
     196           1 :       Tools::convert( mypdb.getAtomNumbers()[0].serial(), atomstr );
     197          13 :       for(unsigned j=1; j<mypdb.getAtomNumbers().size(); ++j ) {
     198          12 :         Tools::convert( mypdb.getAtomNumbers()[j].serial(), num );
     199          24 :         atomstr += "," + num;
     200             :       }
     201           1 :       Tools::convert( mypdb.getResidueNumber( mypdb.getAtomNumbers()[0] ), num );
     202           1 :       atomstr += " RESIDUE_INDICES=" + num;
     203          13 :       for(unsigned i=1; i<mypdb.getAtomNumbers().size(); ++i ) {
     204          12 :         Tools::convert( mypdb.getResidueNumber( mypdb.getAtomNumbers()[i] ), num );
     205          24 :         atomstr += "," + num;
     206             :       }
     207             :       std::string anum, dnum;
     208           1 :       Tools::convert( mypdb.getOccupancy()[0], anum );
     209           1 :       Tools::convert( mypdb.getBeta()[0], dnum );
     210           1 :       atomstr += " OCCUPANCY=" + anum;
     211          13 :       for(unsigned i=1; i<mypdb.getOccupancy().size(); ++i) {
     212          12 :         Tools::convert( mypdb.getOccupancy()[i], anum );
     213          24 :         atomstr += "," + anum;
     214             :       }
     215           1 :       atomstr += " BETA=" + dnum;
     216          13 :       for(unsigned i=1; i<mypdb.getBeta().size(); ++i) {
     217          12 :         Tools::convert( mypdb.getBeta()[i], dnum );
     218          24 :         atomstr += "," + dnum;
     219             :       }
     220           1 :     }
     221             : 
     222           2 :     if( wfilename.find(".pdb")==std::string::npos ) {
     223           0 :       error("output must be to a pdb file");
     224             :     }
     225             :     std::string ofmt, pframes, wstride;
     226           2 :     parse("WSTRIDE",wstride);
     227           4 :     parse("FMT",ofmt);
     228           2 :     if( argnames.size()>0 ) {
     229           1 :       std::string argstr = argnames[0];
     230           2 :       for(unsigned i=1; i<argnames.size(); ++i) {
     231           2 :         argstr += "," + argnames[i];
     232             :       }
     233           2 :       readInputLine("DUMPPDB DESCRIPTION=PATH STRIDE=" + wstride + " FMT=" + ofmt + " FILE=" + wfilename + " ARG=" + reference_data );
     234             :     } else {
     235           2 :       readInputLine("DUMPPDB DESCRIPTION=PATH STRIDE=" + wstride + " FMT=" + ofmt + " FILE=" + wfilename + " ATOMS=" + reference_data + " ATOM_INDICES=" + atomstr );
     236             :     }
     237             :   }
     238           4 :   log<<"  Bibliography "<<plumed.cite("Diaz Leines and Ensing, Phys. Rev. Lett. 109, 020601 (2012)")<<"\n";
     239           4 : }
     240             : 
     241             : }
     242             : }

Generated by: LCOV version 1.16