LCOV - code coverage report
Current view: top level - mapping - PathTools.cpp (source / functions) Hit Total Coverage
Test: plumed test coverage Lines: 358 377 95.0 %
Date: 2025-04-08 21:11:17 Functions: 8 8 100.0 %

          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/CLTool.h"
      23             : #include "core/CLToolRegister.h"
      24             : #include "tools/Tools.h"
      25             : #include "tools/Pbc.h"
      26             : #include "tools/PDB.h"
      27             : #include "core/ActionWithValue.h"
      28             : #include "core/ActionToPutData.h"
      29             : #include "core/ActionSet.h"
      30             : #include "core/Value.h"
      31             : #include "core/PlumedMain.h"
      32             : #include "Path.h"
      33             : #include <cstdio>
      34             : #include <string>
      35             : #include <vector>
      36             : #include <iostream>
      37             : 
      38             : namespace PLMD {
      39             : namespace mapping {
      40             : 
      41             : //+PLUMEDOC TOOLS pathtools
      42             : /*
      43             : pathtools can be used to construct paths from pdb data
      44             : 
      45             : The path CVs in PLUMED are curvilinear coordinates through a high dimensional vector space.
      46             : Enhanced sampling calculations are often run using the progress along the paths and the distance from the path as CVs
      47             : as this provides a convenient way of defining a reaction coordinate for a complicated process.  This method is explained
      48             : in the documentation for \ref PATH.
      49             : 
      50             : The path itself is an ordered set of equally-spaced, high-dimensional frames the way in which these frames
      51             : should be constructed will depend on the problem in hand.  In other words, you will need to understand the reaction
      52             : you wish to study in order to select a sensible set of frames to use in your path CV.  This tool provides two
      53             : methods that may be useful when it comes to constructing paths; namely:
      54             : 
      55             : - A tool that takes in an initial guess path in which the frames are not equally spaced.  This tool adjusts the positions
      56             : of the frames in order to make them equally spaced so that they can be used as the basis for a path CV.
      57             : 
      58             : - A tool that takes two frames as input and that allows you to return a linear path connecting these two frames.  The
      59             : output from this method may be useful as an initial guess path.  It is arguable that a linear path rather defeats the
      60             : purpose of the path CV method, however, as the whole purpose is to be able to define non-linear paths.
      61             : 
      62             : Notice that you can use these two methods and take advantage of all the ways of measuring \ref dists that are available within
      63             : PLUMED. The way you do this with each of these tools described above is explained in the example below.
      64             : 
      65             : \par Examples
      66             : 
      67             : The example below shows how you can take a set of unequally spaced frames from a pdb file named in_path.pdb
      68             : and use pathtools to make them equally spaced so that they can be used as the basis for a path CV.  The file
      69             : containing this final path is named final_path.pdb.
      70             : 
      71             : \verbatim
      72             : plumed pathtools --path in_path.pdb --metric EUCLIDEAN --out final_path.pdb
      73             : \endverbatim
      74             : 
      75             : The example below shows how can create an initial linear path connecting the two pdb frames in start.pdb and
      76             : end.pdb.  In this case the path output to path.pdb will consist of 6 frames: the initial and final frames that
      77             : were contained in start.pdb and end.pdb as well as four equally spaced frames along the vector connecting
      78             : start.pdb to end.pdb.
      79             : 
      80             : \verbatim
      81             : plumed pathtools --start start.pdb --end end.pdb --nframes 4 --metric OPTIMAL --out path.pdb
      82             : \endverbatim
      83             : 
      84             : Often the idea with path collective variables is to create a path connecting some initial state A to some final state B.  You would
      85             : in this case have representative configurations from your A and B states defined in the input files to pathtools
      86             : that we have called start.pdb and end.pdb in the example above.  Furthermore, it may be useful to have a few frames
      87             : before your start frame and after your end frame.  You can use path tools to create these extended paths as shown below.
      88             : In this case the final path would now consist of 8 frames.  Four of these frames would lie on the vector connecting state
      89             : A to state B, there would be one frame each at start.pdb and end.pdb as well as one frame just before start.pdb and one
      90             : frame just after end.pdb.  All these frames would be equally spaced.
      91             : 
      92             : \verbatim
      93             : plumed pathtools --start start.pdb --end end.pdb --nframes 4 --metric OPTIMAL --out path.pdb --nframes-before-start 2 --nframes-after-end 2
      94             : \endverbatim
      95             : 
      96             : Notice also that when you re-parameterize paths you must choose two frames to fix.  Generally you chose to fix the states
      97             : that are representative of your states A and B.  By default pathtools will fix the first and last frames.  You can, however,
      98             : change the states to fix by taking advantage of the fixed flag as shown below.
      99             : 
     100             : \verbatim
     101             : plumed pathtools --path inpath.pdb --metric EUCLIDEAN --out outpath.pdb --fixed 2,12
     102             : \endverbatim
     103             : 
     104             : */
     105             : //+ENDPLUMEDOC
     106             : 
     107             : class PathTools :
     108             :   public CLTool {
     109             : public:
     110             :   static void registerKeywords( Keywords& keys );
     111             :   explicit PathTools(const CLToolOptions& co );
     112             :   int main(FILE* in, FILE*out,Communicator& pc);
     113             :   void printLambda( const std::string& mtype, const std::vector<std::string>& argstr, const std::string& ofile );
     114           5 :   std::string description()const {
     115           5 :     return "print out a description of the keywords for an action in html";
     116             :   }
     117             : };
     118             : 
     119       16263 : PLUMED_REGISTER_CLTOOL(PathTools,"pathtools")
     120             : 
     121        5418 : void PathTools::registerKeywords( Keywords& keys ) {
     122        5418 :   CLTool::registerKeywords( keys );
     123        5418 :   keys.add("atoms","--start","a pdb file that contains the structure for the initial frame of your path");
     124        5418 :   keys.add("atoms","--end","a pdb file that contains the structure for the final frame of your path");
     125        5418 :   keys.add("atoms-1","--path","a pdb file that contains an initial path in which the frames are not equally spaced");
     126        5418 :   keys.add("optional","--arg","the arguments that should be read in from the pdb files");
     127        5418 :   keys.add("compulsory","--fixed","0","the frames to fix when constructing the path using --path");
     128        5418 :   keys.add("compulsory","--metric","the measure to use to calculate the distance between frames");
     129        5418 :   keys.add("compulsory","--out","the name of the file on which to output your path");
     130        5418 :   keys.add("compulsory","--arg-fmt","%f","the format to use for argument values in your frames");
     131        5418 :   keys.add("compulsory","--tolerance","1E-4","the tolerance to use for the algorithm that is used to re-parameterize the path");
     132        5418 :   keys.add("compulsory","--nframes-before-start","1","the number of frames to include in the path before the first frame");
     133        5418 :   keys.add("compulsory","--nframes","1","the number of frames between the start and end frames in your path");
     134        5418 :   keys.add("compulsory","--nframes-after-end","1","the number of frames to put after the last frame of your path");
     135        5418 : }
     136             : 
     137           9 : PathTools::PathTools(const CLToolOptions& co ):
     138           9 :   CLTool(co) {
     139           9 :   inputdata=commandline;
     140           9 : }
     141             : 
     142           4 : int PathTools::main(FILE* in, FILE*out,Communicator& pc) {
     143             :   // Create a PLUMED object
     144           4 :   PlumedMain plmd;
     145           4 :   int s=sizeof(double);
     146           4 :   plmd.cmd("setRealPrecision",&s);
     147           4 :   plmd.cmd("setMDEngine","pathtools");
     148             :   // plmd.cmd("setNoVirial");
     149           4 :   double tstep=1.0;
     150           4 :   plmd.cmd("setTimestep",&tstep);
     151           4 :   plmd.cmd("init");
     152           4 :   int step=1;
     153           4 :   plmd.cmd("setStep",&step);
     154             : 
     155             :   std::string mtype;
     156           8 :   parse("--metric",mtype);
     157             :   std::string ifilename;
     158           8 :   parse("--path",ifilename);
     159             :   std::string ofmt;
     160           8 :   parse("--arg-fmt",ofmt);
     161             :   std::string ofilename;
     162           8 :   parse("--out",ofilename);
     163             :   std::vector<std::string> argstr;
     164           8 :   parseVector("--arg",argstr);
     165           4 :   if( ifilename.length()>0 ) {
     166             :     fprintf(out,"Reparameterising path in file named %s so that all frames are equally spaced \n",ifilename.c_str() );
     167           2 :     FILE* fp=fopen(ifilename.c_str(),"r");
     168           2 :     PDB mypdb;
     169           2 :     bool do_read=mypdb.readFromFilepointer(fp,false,0.1);
     170           2 :     std::vector<double> alig( mypdb.getOccupancy() ), disp( mypdb.getBeta() );
     171           2 :     std::vector<AtomNumber> indices( mypdb.getAtomNumbers() );
     172           2 :     std::vector<unsigned> residue_indices( indices.size() );
     173          15 :     for(unsigned i=0; i<residue_indices.size(); ++i) {
     174          13 :       residue_indices[i] = mypdb.getResidueNumber( indices[i] );
     175             :     }
     176             :     // Count the number of frames in the input file
     177             :     unsigned nfram=1;
     178          20 :     while ( do_read ) {
     179          20 :       if( !mypdb.readFromFilepointer(fp,false,0.1) ) {
     180             :         break;
     181             :       }
     182          18 :       nfram++;
     183             :     }
     184           2 :     if( argstr.size()>0 ) {
     185           3 :       for(unsigned i=0; i<argstr.size(); ++i ) {
     186           4 :         std::string input = argstr[i] + ": PDB2CONSTANT NOARGS REFERENCE=" + ifilename + " ARG=" + argstr[i];
     187             :         const char* inpt = input.c_str();
     188           2 :         plmd.cmd("readInputLine", inpt);
     189             :       }
     190             :     } else {
     191           1 :       std::string input = "data: PDB2CONSTANT REFERENCE=" + ifilename;
     192             :       const char* inpt = input.c_str();
     193           1 :       plmd.cmd("readInputLine", inpt );
     194             :     }
     195           2 :     std::string reparam_str = "REPARAMETERIZE_PATH REFERENCE=";
     196           2 :     if( argstr.size()>0 ) {
     197             :       reparam_str += argstr[0];
     198           3 :       for(unsigned i=0; i<argstr.size(); ++i ) {
     199           4 :         reparam_str += "," + argstr[i];
     200             :       }
     201             :     } else {
     202             :       reparam_str += "data";
     203             :     }
     204             :     std::vector<unsigned> fixed;
     205           4 :     parseVector("--fixed",fixed);
     206           2 :     if( fixed.size()==1 ) {
     207           1 :       if( fixed[0]!=0 ) {
     208           0 :         error("input to --fixed should be two integers");
     209             :       }
     210           1 :       fixed.resize(2);
     211           1 :       fixed[0]=1;
     212           1 :       fixed[1]=nfram;
     213           1 :     } else if( fixed.size()==2 ) {
     214           1 :       if( fixed[0]<1 || fixed[1]<1 || fixed[0]>nfram || fixed[1]>nfram ) {
     215           0 :         error("input to --fixed should be two numbers between 0 and the number of frames-1");
     216             :       }
     217             :     } else {
     218           0 :       error("input to --fixed should be two integers");
     219             :     }
     220             :     std::string fix1, fix2;
     221           2 :     Tools::convert( fixed[0], fix1 );
     222           2 :     Tools::convert( fixed[1], fix2 );
     223           4 :     reparam_str += " FIXED=" + fix1 + "," + fix2;
     224             :     std::string tol;
     225           2 :     parse("--tolerance",tol);
     226           4 :     reparam_str += " TOL=" + tol;
     227             : // Now create the metric object
     228             :     reparam_str += " METRIC=";
     229           5 :     if( mtype=="OPTIMAL-FAST" || mtype=="OPTIMAL" || mtype=="SIMPLE" ) {
     230           2 :       reparam_str += "{RMSD_VECTOR DISPLACEMENT SQUARED UNORMALIZED TYPE=" + mtype;
     231             :       // Get the align values
     232             :       std::string anum;
     233           1 :       Tools::convert( alig[0], anum );
     234           1 :       reparam_str += " ALIGN=" + anum;
     235          13 :       for(unsigned i=1; i<alig.size(); ++i) {
     236          12 :         Tools::convert( alig[i], anum );
     237          24 :         reparam_str += "," + anum;
     238             :       }
     239             :       // Get the displace values
     240             :       std::string dnum;
     241           1 :       Tools::convert( disp[0], dnum );
     242           1 :       reparam_str += " DISPLACE=" + dnum;
     243          13 :       for(unsigned i=1; i<disp.size(); ++i) {
     244          12 :         Tools::convert( disp[i], dnum );
     245          24 :         reparam_str += "," + dnum;
     246             :       }
     247             :       reparam_str += "} METRIC_COMPONENT=disp";
     248           1 :     } else if( mtype=="EUCLIDEAN" ) {
     249             :       reparam_str += "DIFFERENCE";
     250             :     } else {
     251             :       // Add functionality to read plumed input here
     252           0 :       plumed_merror("metric type " + mtype + " has not been implemented");
     253             :     }
     254             : 
     255             :     // Now do the reparameterization
     256             :     const char* icinp= reparam_str.c_str();
     257           2 :     plmd.cmd("readInputLine",icinp);
     258             :     Action* raction = plmd.getActionSet()[plmd.getActionSet().size()-1].get();
     259           2 :     raction->update();
     260             : 
     261             :     // And print the final reference configurations
     262           4 :     std::string pinput="DUMPPDB STRIDE=1 DESCRIPTION=PATH FILE=" + ofilename + " FMT=" + ofmt;
     263           2 :     if( argstr.size()>0 ) {
     264           1 :       pinput += " ARG=" + argstr[0];
     265           2 :       for(unsigned i=1; i<argstr.size(); ++i ) {
     266           2 :         pinput += "," + argstr[i];
     267             :       }
     268             :     } else {
     269             :       std::string num;
     270           1 :       Tools::convert( indices[0].serial(), num );
     271           1 :       pinput += " ATOMS=data ATOM_INDICES=" + num;
     272          13 :       for(unsigned i=1; i<indices.size(); ++i ) {
     273          12 :         Tools::convert( indices[i].serial(), num );
     274          24 :         pinput += "," + num;
     275             :       }
     276           1 :       Tools::convert( residue_indices[0], num );
     277           1 :       pinput += " RESIDUE_INDICES=" + num;
     278          13 :       for(unsigned i=1; i<residue_indices.size(); ++i ) {
     279          12 :         Tools::convert( residue_indices[i], num );
     280          24 :         pinput += "," + num;
     281             :       }
     282             :       std::string anum, dnum;
     283           1 :       Tools::convert( alig[0], anum );
     284           1 :       Tools::convert( disp[0], dnum );
     285           1 :       pinput += " OCCUPANCY=" + anum;
     286          13 :       for(unsigned i=1; i<alig.size(); ++i) {
     287          12 :         Tools::convert( alig[i], anum );
     288          24 :         pinput += "," + anum;
     289             :       }
     290           1 :       pinput += " BETA=" + dnum;
     291          13 :       for(unsigned i=1; i<disp.size(); ++i) {
     292          12 :         Tools::convert( disp[i], dnum );
     293          24 :         pinput += "," + dnum;
     294             :       }
     295             :     }
     296             :     const char* pcinp=pinput.c_str();
     297           2 :     plmd.cmd("readInputLine",pcinp);
     298             :     Action* paction = plmd.getActionSet()[plmd.getActionSet().size()-1].get();
     299           2 :     paction->update();
     300             : 
     301             :     // Ouput data on spacings
     302           2 :     printLambda( mtype, argstr, ofilename );
     303             :     return 0;
     304           2 :   }
     305           4 :   for(unsigned i=0; i<argstr.size(); ++i) {
     306           2 :     std::string input = argstr[i] + ": CONSTANT VALUE=1";
     307             :     const char* inpt = input.c_str();
     308           2 :     plmd.cmd("readInputLine", inpt);
     309             :   }
     310             : 
     311             : // Read in the instructions
     312             :   unsigned nbefore, nbetween, nafter;
     313             :   std::string istart;
     314           4 :   parse("--start",istart);
     315             :   std::string iend;
     316           2 :   parse("--end",iend);
     317           2 :   parse("--nframes-before-start",nbefore);
     318           2 :   parse("--nframes",nbetween);
     319           2 :   parse("--nframes-after-end",nafter);
     320           2 :   nbetween++;
     321             :   fprintf(out,"Generating linear path connecting structure in file named %s to structure in file named %s \n",istart.c_str(),iend.c_str() );
     322           2 :   fprintf(out,"A path consisting of %u equally-spaced frames before the initial structure, %u frames between the initial and final structures "
     323             :           "and %u frames after the final structure will be created \n",nbefore,nbetween,nafter);
     324             : 
     325           2 :   std::vector<double> start_pos( argstr.size() ), end_pos( argstr.size() );
     326             :   std::vector<AtomNumber> indices;
     327           2 :   if( argstr.size()>0 ) {
     328           3 :     for(unsigned i=0; i<argstr.size(); ++i ) {
     329           4 :       std::string input = argstr[i] + "_start: PDB2CONSTANT REFERENCE=" + istart + " ARG=" + argstr[i];
     330             :       const char* inpt = input.c_str();
     331           2 :       plmd.cmd("readInputLine", inpt );
     332             :       long srank;
     333           4 :       plmd.cmd("getDataRank " + argstr[i] + "_start", &srank );
     334           2 :       if( srank!=1 ) {
     335           0 :         error("should only be one frame in input pdb");
     336             :       }
     337           2 :       std::vector<long> sshape( 1 );
     338           4 :       plmd.cmd("getDataShape " + argstr[i] + "_start", &sshape[0] );
     339           2 :       if( sshape[0]!=1 ) {
     340           0 :         error("should only be one frame in input pdb");
     341             :       }
     342           4 :       plmd.cmd("setMemoryForData " + argstr[i] + "_start", &start_pos[i] );
     343           4 :       std::string input2 = argstr[i] + "_end: PDB2CONSTANT REFERENCE=" + iend + " ARG=" + argstr[i];
     344             :       const char* inpt2 = input2.c_str();
     345           2 :       plmd.cmd("readInputLine", inpt2 );
     346             :       long erank;
     347           4 :       plmd.cmd("getDataRank " + argstr[i] + "_end", &erank );
     348           2 :       if( erank!=1 ) {
     349           0 :         error("should only be one frame in input pdb");
     350             :       }
     351           2 :       std::vector<long> eshape( 1 );
     352           4 :       plmd.cmd("getDataShape " + argstr[i] + "_end", &eshape[0] );
     353           2 :       if( eshape[0]!=1 ) {
     354           0 :         error("should only be one frame in input pdb");
     355             :       }
     356           4 :       plmd.cmd("setMemoryForData " + argstr[i] + "_end", &end_pos[i] );
     357             :     }
     358             :   } else {
     359           1 :     std::string input = "start: PDB2CONSTANT REFERENCE=" + istart;
     360             :     const char* inpt = input.c_str();
     361           1 :     plmd.cmd("readInputLine", inpt );
     362           1 :     FILE* fp=fopen(istart.c_str(),"r");
     363           1 :     PDB mypdb;
     364           1 :     bool do_read=mypdb.readFromFilepointer(fp,false,0.1);
     365           1 :     indices.resize( mypdb.getAtomNumbers().size() );
     366          14 :     for(unsigned i=0; i<indices.size(); ++i) {
     367          13 :       indices[i] = mypdb.getAtomNumbers()[i];
     368             :     }
     369             :     long srank;
     370           1 :     plmd.cmd("getDataRank start", &srank );
     371           1 :     if( srank!=2 ) {
     372           0 :       error("should only be one frame in input pdb:" + istart);
     373             :     }
     374           1 :     std::vector<long> sshape( srank );
     375           1 :     plmd.cmd("getDataShape start", &sshape[0] );
     376           1 :     start_pos.resize( sshape[0]*sshape[1] );
     377           1 :     if( sshape[0]!=1 ) {
     378           0 :       error("should only be one frame in input pdb: " + istart);
     379             :     }
     380           1 :     plmd.cmd("setMemoryForData start", &start_pos[0] );
     381           1 :     std::string input2 = "end: PDB2CONSTANT REFERENCE=" + iend;
     382             :     const char* inpt2 = input2.c_str();
     383           1 :     plmd.cmd("readInputLine", inpt2 );
     384             :     long erank;
     385           1 :     plmd.cmd("getDataRank end", &erank );
     386           1 :     if( erank!=2 ) {
     387           0 :       error("should only be one frame in input pdb: " + iend);
     388             :     }
     389           1 :     std::vector<long> eshape( erank );
     390           1 :     plmd.cmd("getDataShape end", &eshape[0] );
     391           1 :     end_pos.resize( eshape[0]*eshape[1] );
     392           1 :     if( eshape[0]!=1 ) {
     393           0 :       error("should only be one frame in input pdb: " + iend );
     394             :     }
     395           1 :     plmd.cmd("setMemoryForData end", &end_pos[0] );
     396           1 :   }
     397             : 
     398             : // Now create the metric object
     399             :   std::vector<double> alig, disp;
     400             :   std::vector<unsigned> residue_indices;
     401           5 :   if( mtype=="OPTIMAL-FAST" || mtype=="OPTIMAL" || mtype=="SIMPLE" ) {
     402           1 :     std::string trinput = "endT: TRANSPOSE ARG=end";
     403             :     const char* tinp=trinput.c_str();
     404           1 :     plmd.cmd("readInputLine",tinp);
     405           1 :     PDB pdb;
     406           1 :     pdb.read(istart,false,0.1);
     407           1 :     alig.resize( pdb.getOccupancy().size() );
     408           1 :     disp.resize( pdb.getBeta().size() );
     409          14 :     for(unsigned i=0; i<alig.size(); ++i) {
     410          13 :       alig[i] = pdb.getOccupancy()[i];
     411          13 :       disp[i]= pdb.getBeta()[i];
     412             :     }
     413           2 :     std::string minput = "d: RMSD_VECTOR DISPLACEMENT SQUARED UNORMALIZED TYPE=" + mtype + " ARG=endT,start";
     414             :     // Get the align values
     415             :     std::string anum;
     416           1 :     Tools::convert( alig[0], anum );
     417           1 :     minput += " ALIGN=" + anum;
     418          13 :     for(unsigned i=1; i<alig.size(); ++i) {
     419          12 :       Tools::convert( alig[i], anum );
     420          24 :       minput += "," + anum;
     421             :     }
     422             :     // Get the displace values
     423             :     std::string dnum;
     424           1 :     Tools::convert( disp[0], dnum );
     425           1 :     minput += " DISPLACE=" + dnum;
     426          13 :     for(unsigned i=1; i<disp.size(); ++i) {
     427          12 :       Tools::convert( disp[i], dnum );
     428          24 :       minput += "," + dnum;
     429             :     }
     430             :     const char* mcinp=minput.c_str();
     431           1 :     plmd.cmd("readInputLine",mcinp);
     432           1 :     std::string tinput = "CUSTOM ARG=d.disp FUNC=x PERIODIC=NO";
     433             :     const char* tcinp=tinput.c_str();
     434           1 :     plmd.cmd("readInputLine",tcinp);
     435             :     // Get the residue numbers
     436           1 :     residue_indices.resize( pdb.size() );
     437          14 :     for(unsigned i=0; i<residue_indices.size(); ++i) {
     438          13 :       residue_indices[i] = pdb.getResidueNumber( indices[i] );
     439             :     }
     440           2 :   } else if( mtype=="EUCLIDEAN" ) {
     441           2 :     std::string end_args="ARG1=" + argstr[0] + "_end", start_args="ARG2=" + argstr[0] + "_start";
     442           2 :     for(unsigned i=1; i<argstr.size(); ++i ) {
     443           2 :       end_args += "," + argstr[i] + "_end";
     444           2 :       start_args += "," + argstr[i] + "_start";
     445             :     }
     446           2 :     std::string minput = "d: DISPLACEMENT " + end_args + " " + start_args;
     447             :     const char* mcinp=minput.c_str();
     448           1 :     plmd.cmd("readInputLine",mcinp);
     449           1 :     std::string tinput = "TRANSPOSE ARG=d";
     450             :     const char* tcinp=tinput.c_str();
     451           1 :     plmd.cmd("readInputLine",tcinp);
     452             :   } else {
     453             :     // Add functionality to read plumed input here
     454           0 :     plumed_merror("metric type " + mtype + " has not been implemented");
     455             :   }
     456             : 
     457             : // Retrieve final displacement vector
     458           2 :   unsigned aind = plmd.getActionSet().size()-1;
     459             :   while( true ) {
     460           3 :     const ActionShortcut* as=dynamic_cast<const ActionShortcut*>( plmd.getActionSet()[aind].get() );
     461           3 :     if( !as ) {
     462             :       break ;
     463             :     }
     464           1 :     aind = aind - 1;
     465             :     plumed_assert( aind>=0 );
     466           1 :   }
     467           2 :   ActionWithValue* av = dynamic_cast<ActionWithValue*>( plmd.getActionSet()[aind].get() );
     468           2 :   if( !av ) {
     469           0 :     error("invalid input for metric" );
     470             :   }
     471           2 :   if( av->getNumberOfComponents()!=1 && av->getName()!="RMSD_VECTOR" ) {
     472           0 :     error("cannot use multi component actions as metric");
     473             :   }
     474           2 :   std::string mydisp = av->copyOutput(0)->getName();
     475             : // Now add calls so we can grab the data from plumed
     476             :   long rank;
     477           4 :   plmd.cmd("getDataRank " + mydisp, &rank );
     478           2 :   if( rank!=1 ) {
     479           0 :     error("displacement must be a vector quantity");
     480             :   }
     481           2 :   std::vector<long> ishape( rank );
     482           4 :   plmd.cmd("getDataShape " + mydisp, &ishape[0] );
     483           2 :   std::vector<double> displacement( ishape[0] );
     484           4 :   plmd.cmd("setMemoryForData " + mydisp, &displacement[0] );
     485             : // And calculate the displacement
     486           2 :   plmd.cmd("calc");
     487             : 
     488             :   // Now read in the initial frame
     489             : 
     490             :   // Now create frames
     491           2 :   double delr = 1.0 / static_cast<double>( nbetween );
     492             :   std::vector<std::vector<double> > allframes;
     493           2 :   std::vector<double> frame( displacement.size() );
     494           4 :   for(int i=0; i<nbefore; ++i) {
     495          43 :     for(unsigned j=0; j<frame.size(); ++j) {
     496          41 :       frame[j] = start_pos[j] - i*delr*displacement[j];
     497             :     }
     498           2 :     allframes.push_back( frame );
     499             :   }
     500           8 :   for(unsigned i=1; i<nbetween; ++i) {
     501          55 :     for(unsigned j=0; j<frame.size(); ++j) {
     502          49 :       frame[j] = start_pos[j] + i*delr*displacement[j];
     503             :     }
     504           6 :     allframes.push_back( frame );
     505             :   }
     506           7 :   for(unsigned i=0; i<nafter; ++i) {
     507          52 :     for(unsigned j=0; j<frame.size(); ++j) {
     508          47 :       frame[j] = end_pos[j] + i*delr*displacement[j];
     509             :     }
     510           5 :     allframes.push_back( frame );
     511             :   }
     512             :   // This prints out our final reference configurations
     513           2 :   plmd.cmd("clear");
     514           4 :   plmd.readInputLine("timestep: PUT UNIT=time PERIODIC=NO CONSTANT");
     515           2 :   ActionToPutData* ts = plmd.getActionSet().selectWithLabel<ActionToPutData*>("timestep");
     516           4 :   ts->setValuePointer("timestep", &tstep );
     517           4 :   std::string pinput="DUMPPDB STRIDE=1 DESCRIPTION=PATH FILE=" + ofilename + " FMT=" + ofmt;
     518           2 :   if( argstr.size()>0 ) {
     519           3 :     for(unsigned i=0; i<argstr.size(); ++i) {
     520             :       std::string rnum;
     521           2 :       Tools::convert( allframes[0][i], rnum );
     522           2 :       std::string inpt = argstr[i] + ": CONSTANT VALUES=" + rnum;
     523          20 :       for(unsigned j=1; j<allframes.size(); ++j) {
     524          18 :         Tools::convert( allframes[j][i], rnum );
     525          36 :         inpt += "," + rnum;
     526             :       }
     527             :       const char* icinp=inpt.c_str();
     528           2 :       plmd.cmd("readInputLine",icinp);
     529           2 :       if( i==0 ) {
     530           2 :         pinput += " ARG=" + argstr[i];
     531             :       } else {
     532           2 :         pinput += "," + argstr[i];
     533             :       }
     534             :     }
     535             :   } else {
     536             :     std::string nc;
     537           1 :     Tools::convert( frame.size(), nc );
     538             :     std::string nr;
     539           1 :     Tools::convert( allframes.size(), nr );
     540             :     std::string rnum;
     541           1 :     Tools::convert( allframes[0][0], rnum );
     542           2 :     std::string inpt = "atom_data: CONSTANT NROWS=" + nr + " NCOLS=" + nc + " VALUES=" + rnum;
     543           4 :     for(unsigned i=0; i<allframes.size(); ++i) {
     544         120 :       for(unsigned j=0; j<allframes[i].size(); ++j) {
     545         117 :         if( i==0 && j==0 ) {
     546           1 :           continue;
     547             :         }
     548         116 :         Tools::convert( allframes[i][j], rnum );
     549         232 :         inpt += "," + rnum;
     550             :       }
     551             :     }
     552             :     const char* icinp=inpt.c_str();
     553           1 :     plmd.cmd("readInputLine",icinp);
     554             :     std::string num;
     555           1 :     Tools::convert( indices[0].serial(), num );
     556           1 :     pinput += " ATOMS=atom_data ATOM_INDICES=" + num;
     557          13 :     for(unsigned i=1; i<indices.size(); ++i ) {
     558          12 :       Tools::convert( indices[i].serial(), num );
     559          24 :       pinput += "," + num;
     560             :     }
     561           1 :     Tools::convert( residue_indices[0], num );
     562           1 :     pinput += " RESIDUE_INDICES=" + num;
     563          13 :     for(unsigned i=1; i<residue_indices.size(); ++i ) {
     564          12 :       Tools::convert( residue_indices[i], num );
     565          24 :       pinput += "," + num;
     566             :     }
     567             :     std::string anum, dnum;
     568           1 :     Tools::convert( alig[0], anum );
     569           1 :     Tools::convert( disp[0], dnum );
     570           1 :     pinput += " OCCUPANCY=" + anum;
     571          13 :     for(unsigned i=1; i<alig.size(); ++i) {
     572          12 :       Tools::convert( alig[i], anum );
     573          24 :       pinput += "," + anum;
     574             :     }
     575           1 :     pinput += " BETA=" + dnum;
     576          13 :     for(unsigned i=1; i<disp.size(); ++i) {
     577          12 :       Tools::convert( disp[i], dnum );
     578          24 :       pinput += "," + dnum;
     579             :     }
     580             :   }
     581             :   const char* pcinp=pinput.c_str();
     582           2 :   plmd.cmd("readInputLine",pcinp);
     583             :   Action* paction = plmd.getActionSet()[plmd.getActionSet().size()-1].get();
     584           2 :   paction->update();
     585             :   // And output suggestions on the value of Lambda
     586           2 :   printLambda( mtype, argstr, ofilename );
     587             :   return 0;
     588          10 : }
     589             : 
     590           4 : void PathTools::printLambda( const std::string& mtype, const std::vector<std::string>& argstr, const std::string& ofile ) {
     591             :   // Create a PLUMED object
     592           4 :   PlumedMain plmd;
     593           4 :   int s=sizeof(double);
     594           4 :   plmd.cmd("setRealPrecision",&s);
     595           4 :   plmd.cmd("setMDEngine","pathtools");
     596           4 :   double tstep=1.0;
     597           4 :   plmd.cmd("setTimestep",&tstep);
     598           4 :   plmd.cmd("init");
     599           4 :   int step=1;
     600           4 :   plmd.cmd("setStep",&step);
     601             : 
     602           4 :   FILE* fp=fopen(ofile.c_str(),"r");
     603             :   bool do_read=true;
     604             :   unsigned nfram=0;
     605             :   std::vector<double> alig, disp;
     606             :   // Read in the argument names
     607           8 :   for(unsigned i=0; i<argstr.size(); ++i ) {
     608           4 :     std::string input2 = argstr[i] + ": CONSTANT VALUE=1";
     609             :     const char* inpt2 = input2.c_str();
     610           4 :     plmd.cmd("readInputLine", inpt2);
     611             :   }
     612          37 :   while (do_read ) {
     613          37 :     PDB mypdb;
     614             :     // Read the pdb file
     615          37 :     do_read=mypdb.readFromFilepointer(fp,false,0.1);
     616          37 :     if( !do_read ) {
     617             :       break;
     618             :     }
     619             :     std::string num;
     620          33 :     Tools::convert( nfram+1, num );
     621             :     nfram++;
     622             :     std::string iinput;
     623          33 :     if( argstr.size()>0 ) {
     624          60 :       for(unsigned i=0; i<argstr.size(); ++i ) {
     625          80 :         std::string input = "ref_" + num + "_" + argstr[i] + ": PDB2CONSTANT REFERENCE=" + ofile + " ARG=" + argstr[i] + " NUMBER=" + num;
     626             :         const char* inpt = input.c_str();
     627          40 :         plmd.cmd("readInputLine", inpt );
     628             :       }
     629             :     } else {
     630          26 :       std::string input = "ref_" + num + ": PDB2CONSTANT REFERENCE=" + ofile + " NUMBER=" + num;
     631             :       const char* inpt = input.c_str();
     632          13 :       plmd.cmd("readInputLine", inpt );
     633             :     }
     634             : 
     635          33 :     if( nfram==1 ) {
     636           4 :       alig.resize( mypdb.getOccupancy().size() );
     637          30 :       for(unsigned i=0; i<alig.size(); ++i) {
     638          26 :         alig[i]=mypdb.getOccupancy()[i];
     639             :       }
     640           4 :       disp.resize( mypdb.getBeta().size() );
     641          30 :       for(unsigned i=0; i<disp.size(); ++i) {
     642          26 :         disp[i]=mypdb.getBeta()[i];
     643             :       }
     644             :     }
     645          37 :   }
     646             :   // Now create the objects to measure the distances between the frames
     647           4 :   std::vector<double> data( nfram );
     648          33 :   for(unsigned j=1; j<nfram; ++j) {
     649             :     std::string istr, jstr;
     650          29 :     Tools::convert( j, istr);
     651          29 :     Tools::convert( j+1, jstr );
     652          76 :     if( mtype=="OPTIMAL-FAST" || mtype=="OPTIMAL" || mtype=="SIMPLE" ) {
     653          22 :       std::string strv = "ref_" + jstr + "T: TRANSPOSE ARG=ref_" + jstr;
     654             :       const char* cstrv = strv.c_str();
     655          11 :       plmd.cmd("readInputLine",cstrv);
     656          22 :       std::string dstring = "d" + istr + ": RMSD_VECTOR TYPE=" + mtype + " ARG=ref_" + jstr + "T,ref_" + istr;
     657             :       // Get the align values
     658             :       std::string anum;
     659          11 :       Tools::convert( alig[0], anum );
     660          11 :       dstring += " ALIGN=" + anum;
     661         143 :       for(unsigned i=1; i<alig.size(); ++i) {
     662         132 :         Tools::convert( alig[i], anum );
     663         264 :         dstring += "," + anum;
     664             :       }
     665             :       // Get the displace values
     666             :       std::string dnum;
     667          11 :       Tools::convert( disp[0], dnum );
     668          11 :       dstring += " DISPLACE=" + dnum;
     669         143 :       for(unsigned i=1; i<disp.size(); ++i) {
     670         132 :         Tools::convert( disp[i], dnum );
     671         264 :         dstring += "," + dnum;
     672             :       }
     673             :       const char* icinp=dstring.c_str();
     674          11 :       plmd.cmd("readInputLine",icinp);
     675          18 :     } else if( mtype=="EUCLIDEAN" ) {
     676          54 :       std::string end_args="ARG1=ref_" + istr + "_" + argstr[0], start_args="ARG2=ref_" + jstr + "_" + argstr[0];
     677          36 :       for(unsigned i=1; i<argstr.size(); ++i ) {
     678          36 :         end_args += ",ref_" + istr + "_" + argstr[i];
     679          36 :         start_args += ",ref_" + jstr + "_" + argstr[i];
     680             :       }
     681          36 :       std::string fstr = "d" + istr + ": EUCLIDEAN_DISTANCE " + end_args + " " + start_args;
     682             :       const char* icinp=fstr.c_str();
     683          18 :       plmd.cmd("readInputLine",icinp);
     684             :     } else {
     685           0 :       plumed_merror("metric type " + mtype + " has not been implemented");
     686             :     }
     687             :     long rank;
     688          58 :     plmd.cmd("getDataRank d" + istr, &rank );
     689          29 :     if( rank!=1 ) {
     690           0 :       error("distance should be of rank 1");
     691             :     }
     692          29 :     std::vector<long> ishape(1);
     693          58 :     plmd.cmd("getDataShape d" + istr, &ishape[0] );
     694          29 :     if( ishape[0]!=1 ) {
     695           0 :       error("distance should be of rank 1");
     696             :     }
     697          58 :     plmd.cmd("setMemoryForData d" + istr, &data[j-1] );
     698             :   }
     699           4 :   plmd.cmd("calc");
     700             :   double mean=0;
     701             :   printf("N.B. THIS CODE ALWAYS AIMS TO CREATE EQUALLY SPACED FRAMES \n");
     702             :   printf("THERE MAY BE SMALL DESCREPENCIES IN THE NUMBERS BELOW, HOWEVER, BECAUSE OF ROUNDING ERRORS \n");
     703          33 :   for(unsigned i=1; i<nfram; ++i) {
     704          29 :     printf("FINAL DISTANCE BETWEEN FRAME %u AND %u IS %f \n",i-1,i,data[i-1]);
     705          29 :     mean += data[i-1];
     706             :   }
     707           4 :   printf("SUGGESTED LAMBDA PARAMETER IS THUS %f \n",2.3/mean/static_cast<double>( nfram-1 ) );
     708           4 : }
     709             : 
     710             : } // End of namespace
     711             : }

Generated by: LCOV version 1.16