Line data Source code
1 : /* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 : Copyright (c) 2011-2023 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/ActionWithArguments.h" 25 : #include "tools/PDB.h" 26 : #include "core/PlumedMain.h" 27 : 28 : namespace PLMD { 29 : namespace colvar { 30 : 31 : class RMSDShortcut : public ActionShortcut { 32 : public: 33 : static void registerKeywords(Keywords& keys); 34 : explicit RMSDShortcut(const ActionOptions&); 35 : }; 36 : 37 : PLUMED_REGISTER_ACTION(RMSDShortcut,"RMSD") 38 : 39 118 : void RMSDShortcut::registerKeywords(Keywords& keys) { 40 118 : ActionShortcut::registerKeywords( keys ); 41 236 : keys.add("compulsory","REFERENCE","a file in pdb format containing the reference structure and the atoms involved in the CV"); 42 236 : keys.add("compulsory","TYPE","SIMPLE","the manner in which RMSD alignment is performed. Should be OPTIMAL or SIMPLE."); 43 236 : keys.addFlag("SQUARED",false," This should be setted if you want MSD instead of RMSD "); 44 236 : keys.addFlag("NOPBC",false,"ignore the periodic boundary conditions when calculating distances"); 45 236 : keys.addFlag("NUMERICAL_DERIVATIVES", false, "calculate the derivatives for these quantities numerically"); 46 236 : keys.addFlag("DISPLACEMENT",false,"Calculate the vector of displacements instead of the length of this vector"); 47 236 : keys.add("compulsory","NUMBER","0","if there are multiple structures in the pdb file you can specify that you want the RMSD from a specific structure by specifying its place in the file here. If NUMBER=0 then the RMSD from all structures are computed"); 48 236 : keys.addOutputComponent("disp","DISPLACEMENT","vector/matrix","the vector of displacements for the atoms"); 49 236 : keys.addOutputComponent("dist","DISPLACEMENT","scalar/vector","the RMSD distance the atoms have moved"); 50 236 : keys.setValueDescription("scalar/vector","the RMSD distance between the instaneous structure and the reference structure/s that were input"); 51 236 : keys.addActionNameSuffix("_SCALAR"); keys.addActionNameSuffix("_VECTOR"); 52 236 : keys.needsAction("PDB2CONSTANT"); keys.needsAction("WHOLEMOLECULES"); 53 236 : keys.needsAction("POSITION"); keys.needsAction("CONCATENATE"); 54 118 : } 55 : 56 104 : RMSDShortcut::RMSDShortcut(const ActionOptions& ao): 57 : Action(ao), 58 104 : ActionShortcut(ao) 59 : { 60 208 : bool disp; parseFlag("DISPLACEMENT",disp); 61 106 : std::string reference; parse("REFERENCE",reference); 62 : // Read the reference pdb file 63 106 : PDB pdb; if( !pdb.read(reference,plumed.usingNaturalUnits(),0.1/plumed.getUnits().getLength()) ) plumed_merror("missing file " + reference ); 64 103 : unsigned frame; parse("NUMBER",frame); unsigned nf=1; 65 103 : if( frame==0 ) { 66 94 : FILE* fp=std::fopen(reference.c_str(),"r"); bool do_read=true; nf=0; 67 561 : while ( do_read ) { 68 495 : PDB mypdb; do_read=mypdb.readFromFilepointer(fp,plumed.usingNaturalUnits(),0.1/plumed.getUnits().getLength()); 69 495 : if( !do_read && nf>0 ) break ; 70 467 : nf++; 71 495 : } 72 : } 73 103 : bool nopbc; parseFlag("NOPBC",nopbc); 74 : // Now create the RMSD object 75 103 : std::string rmsd_line = getShortcutLabel() + ": "; 76 103 : if( nf==1 && !disp ) { 77 162 : rmsd_line += "RMSD_SCALAR REFERENCE=" + reference; if(nopbc) rmsd_line += " NOPBC"; 78 : } else { 79 22 : std::string ffnum; Tools::convert( frame, ffnum ); 80 44 : readInputLine( getShortcutLabel() + "_ref: PDB2CONSTANT REFERENCE=" + reference + " NUMBER=" + ffnum ); 81 22 : std::vector<AtomNumber> anum( pdb.getAtomNumbers() ); 82 22 : if( !nopbc ) { 83 20 : std::string num; Tools::convert( anum[0].serial(), num ); std::string wm_line = "WHOLEMOLECULES ENTITY0=" + num; 84 196 : for(unsigned i=1; i<anum.size(); ++i) { Tools::convert( anum[i].serial(), num ); wm_line += "," + num; } 85 20 : readInputLine( wm_line ); 86 : } 87 22 : std::string num; Tools::convert( anum[0].serial(), num ); std::string pos_line = getShortcutLabel() + "_cpos: POSITION NOPBC ATOMS=" + num; 88 210 : for(unsigned i=1; i<anum.size(); ++i) { Tools::convert( anum[i].serial(), num ); pos_line += "," + num; } 89 22 : readInputLine( pos_line ); 90 : // Concatenate the three positions together 91 44 : readInputLine( getShortcutLabel() + "_pos: CONCATENATE ARG=" + getShortcutLabel() + "_cpos.x," + getShortcutLabel() + "_cpos.y," + getShortcutLabel() + "_cpos.z"); 92 44 : rmsd_line += "RMSD_VECTOR ARG=" + getShortcutLabel() + "_pos," + getShortcutLabel() + "_ref"; 93 22 : if( disp ) rmsd_line += " DISPLACEMENT"; 94 : // Now align 95 22 : std::vector<double> align( pdb.getOccupancy() ); Tools::convert( align[0], num ); rmsd_line += " ALIGN=" + num; 96 210 : for(unsigned i=1; i<align.size(); ++i) { Tools::convert( align[i], num ); rmsd_line += "," + num; } 97 : // And displace 98 22 : std::vector<double> displace( pdb.getBeta() ); Tools::convert( displace[0], num ); rmsd_line += " DISPLACE=" + num; 99 210 : for(unsigned i=1; i<displace.size(); ++i) { Tools::convert( displace[i], num ); rmsd_line += "," + num; } 100 : } 101 : // And create the RMSD object 102 103 : bool numder; parseFlag("NUMERICAL_DERIVATIVES",numder); 103 103 : if(numder && nf==1 && !disp ) rmsd_line += " NUMERICAL_DERIVATIVES"; else if( numder ) error("can only use NUMERICAL_DERIVATIVES flag when RMSD is calculating a single scalar value"); 104 207 : bool squared; parseFlag("SQUARED",squared); if(squared) rmsd_line += " SQUARED"; 105 310 : std::string tt; parse("TYPE",tt); readInputLine( rmsd_line + " TYPE=" + tt ); 106 210 : } 107 : 108 : } 109 : }