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 118 : keys.setValueDescription("the RMSD distance between the instaneous structure and the reference structure/s that were input"); 49 118 : keys.addActionNameSuffix("_SCALAR"); 50 118 : keys.addActionNameSuffix("_VECTOR"); 51 118 : keys.needsAction("PDB2CONSTANT"); 52 118 : keys.needsAction("WHOLEMOLECULES"); 53 118 : keys.needsAction("POSITION"); 54 118 : keys.needsAction("CONCATENATE"); 55 118 : } 56 : 57 104 : RMSDShortcut::RMSDShortcut(const ActionOptions& ao): 58 : Action(ao), 59 104 : ActionShortcut(ao) { 60 : bool disp; 61 208 : parseFlag("DISPLACEMENT",disp); 62 : std::string reference; 63 106 : parse("REFERENCE",reference); 64 : // Read the reference pdb file 65 104 : PDB pdb; 66 104 : if( !pdb.read(reference,plumed.usingNaturalUnits(),0.1/plumed.getUnits().getLength()) ) { 67 3 : plumed_merror("missing file " + reference ); 68 : } 69 : unsigned frame; 70 103 : parse("NUMBER",frame); 71 : unsigned nf=1; 72 103 : if( frame==0 ) { 73 94 : FILE* fp=std::fopen(reference.c_str(),"r"); 74 : bool do_read=true; 75 : nf=0; 76 561 : while ( do_read ) { 77 495 : PDB mypdb; 78 495 : do_read=mypdb.readFromFilepointer(fp,plumed.usingNaturalUnits(),0.1/plumed.getUnits().getLength()); 79 495 : if( !do_read && nf>0 ) { 80 : break ; 81 : } 82 467 : nf++; 83 495 : } 84 : } 85 : bool nopbc; 86 103 : parseFlag("NOPBC",nopbc); 87 : // Now create the RMSD object 88 103 : std::string rmsd_line = getShortcutLabel() + ": "; 89 103 : if( nf==1 && !disp ) { 90 81 : rmsd_line += "RMSD_SCALAR REFERENCE=" + reference; 91 81 : if(nopbc) { 92 : rmsd_line += " NOPBC"; 93 : } 94 : } else { 95 : std::string ffnum; 96 22 : Tools::convert( frame, ffnum ); 97 44 : readInputLine( getShortcutLabel() + "_ref: PDB2CONSTANT REFERENCE=" + reference + " NUMBER=" + ffnum ); 98 22 : std::vector<AtomNumber> anum( pdb.getAtomNumbers() ); 99 22 : if( !nopbc ) { 100 : std::string num; 101 20 : Tools::convert( anum[0].serial(), num ); 102 20 : std::string wm_line = "WHOLEMOLECULES ENTITY0=" + num; 103 196 : for(unsigned i=1; i<anum.size(); ++i) { 104 176 : Tools::convert( anum[i].serial(), num ); 105 352 : wm_line += "," + num; 106 : } 107 20 : readInputLine( wm_line ); 108 : } 109 : std::string num; 110 22 : Tools::convert( anum[0].serial(), num ); 111 22 : std::string pos_line = getShortcutLabel() + "_cpos: POSITION NOPBC ATOMS=" + num; 112 210 : for(unsigned i=1; i<anum.size(); ++i) { 113 188 : Tools::convert( anum[i].serial(), num ); 114 376 : pos_line += "," + num; 115 : } 116 22 : readInputLine( pos_line ); 117 : // Concatenate the three positions together 118 44 : readInputLine( getShortcutLabel() + "_pos: CONCATENATE ARG=" + getShortcutLabel() + "_cpos.x," + getShortcutLabel() + "_cpos.y," + getShortcutLabel() + "_cpos.z"); 119 44 : rmsd_line += "RMSD_VECTOR ARG=" + getShortcutLabel() + "_pos," + getShortcutLabel() + "_ref"; 120 22 : if( disp ) { 121 : rmsd_line += " DISPLACEMENT"; 122 : } 123 : // Now align 124 22 : std::vector<double> align( pdb.getOccupancy() ); 125 22 : Tools::convert( align[0], num ); 126 22 : rmsd_line += " ALIGN=" + num; 127 210 : for(unsigned i=1; i<align.size(); ++i) { 128 188 : Tools::convert( align[i], num ); 129 376 : rmsd_line += "," + num; 130 : } 131 : // And displace 132 22 : std::vector<double> displace( pdb.getBeta() ); 133 22 : Tools::convert( displace[0], num ); 134 22 : rmsd_line += " DISPLACE=" + num; 135 210 : for(unsigned i=1; i<displace.size(); ++i) { 136 188 : Tools::convert( displace[i], num ); 137 376 : rmsd_line += "," + num; 138 : } 139 : } 140 : // And create the RMSD object 141 : bool numder; 142 103 : parseFlag("NUMERICAL_DERIVATIVES",numder); 143 103 : if(numder && nf==1 && !disp ) { 144 : rmsd_line += " NUMERICAL_DERIVATIVES"; 145 98 : } else if( numder ) { 146 0 : error("can only use NUMERICAL_DERIVATIVES flag when RMSD is calculating a single scalar value"); 147 : } 148 : bool squared; 149 104 : parseFlag("SQUARED",squared); 150 103 : if(squared) { 151 : rmsd_line += " SQUARED"; 152 : } 153 : std::string tt; 154 103 : parse("TYPE",tt); 155 207 : readInputLine( rmsd_line + " TYPE=" + tt ); 156 210 : } 157 : 158 : } 159 : }