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 119 : void RMSDShortcut::registerKeywords(Keywords& keys) {
40 119 : ActionShortcut::registerKeywords( keys );
41 119 : keys.add("compulsory","REFERENCE","a file in pdb format containing the reference structure and the atoms involved in the CV");
42 119 : keys.add("compulsory","TYPE","SIMPLE","the manner in which RMSD alignment is performed. Should be OPTIMAL or SIMPLE.");
43 119 : keys.addFlag("SQUARED",false," This should be setted if you want MSD instead of RMSD ");
44 119 : keys.addFlag("NOPBC",false,"ignore the periodic boundary conditions when calculating distances");
45 119 : keys.addFlag("NUMERICAL_DERIVATIVES", false, "calculate the derivatives for these quantities numerically");
46 119 : keys.addFlag("DISPLACEMENT",false,"Calculate the vector of displacements instead of the length of this vector");
47 119 : 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 238 : keys.addOutputComponent("disp","DISPLACEMENT","vector/matrix","the vector of displacements for the atoms");
49 238 : keys.addOutputComponent("dist","DISPLACEMENT","scalar/vector","the RMSD distance the atoms have moved");
50 238 : keys.setValueDescription("scalar/vector","the RMSD distance between the instaneous structure and the reference structure/s that were input");
51 119 : keys.addActionNameSuffix("_SCALAR");
52 119 : keys.addActionNameSuffix("_VECTOR");
53 119 : keys.needsAction("PDB2CONSTANT");
54 119 : keys.needsAction("WHOLEMOLECULES");
55 119 : keys.needsAction("POSITION");
56 119 : keys.needsAction("CONCATENATE");
57 119 : keys.addDOI("10.1107/S0108767388010128");
58 119 : }
59 :
60 105 : RMSDShortcut::RMSDShortcut(const ActionOptions& ao):
61 : Action(ao),
62 105 : ActionShortcut(ao) {
63 : bool disp;
64 210 : parseFlag("DISPLACEMENT",disp);
65 : std::string reference;
66 107 : parse("REFERENCE",reference);
67 : // Read the reference pdb file
68 105 : PDB pdb;
69 105 : if( !pdb.read(reference,plumed.usingNaturalUnits(),0.1/plumed.getUnits().getLength()) ) {
70 3 : plumed_merror("missing file " + reference );
71 : }
72 : unsigned frame;
73 104 : parse("NUMBER",frame);
74 : unsigned nf=1;
75 104 : if( frame==0 ) {
76 95 : FILE* fp=std::fopen(reference.c_str(),"r");
77 : bool do_read=true;
78 : nf=0;
79 563 : while ( do_read ) {
80 496 : PDB mypdb;
81 496 : do_read=mypdb.readFromFilepointer(fp,plumed.usingNaturalUnits(),0.1/plumed.getUnits().getLength());
82 496 : if( !do_read && nf>0 ) {
83 : break ;
84 : }
85 468 : nf++;
86 496 : }
87 : }
88 : bool nopbc;
89 104 : parseFlag("NOPBC",nopbc);
90 : // Now create the RMSD object
91 104 : std::string rmsd_line = getShortcutLabel() + ": ";
92 104 : if( nf==1 && !disp ) {
93 82 : rmsd_line += "RMSD_SCALAR REFERENCE=" + reference;
94 82 : if(nopbc) {
95 : rmsd_line += " NOPBC";
96 : }
97 : } else {
98 : std::string ffnum;
99 22 : Tools::convert( frame, ffnum );
100 44 : readInputLine( getShortcutLabel() + "_ref: PDB2CONSTANT REFERENCE=" + reference + " NUMBER=" + ffnum );
101 22 : std::vector<AtomNumber> anum( pdb.getAtomNumbers() );
102 22 : if( !nopbc ) {
103 : std::string num;
104 20 : Tools::convert( anum[0].serial(), num );
105 20 : std::string wm_line = "WHOLEMOLECULES ENTITY0=" + num;
106 196 : for(unsigned i=1; i<anum.size(); ++i) {
107 176 : Tools::convert( anum[i].serial(), num );
108 352 : wm_line += "," + num;
109 : }
110 20 : readInputLine( wm_line );
111 : }
112 : std::string num;
113 22 : Tools::convert( anum[0].serial(), num );
114 22 : std::string pos_line = getShortcutLabel() + "_cpos: POSITION NOPBC ATOMS=" + num;
115 210 : for(unsigned i=1; i<anum.size(); ++i) {
116 188 : Tools::convert( anum[i].serial(), num );
117 376 : pos_line += "," + num;
118 : }
119 22 : readInputLine( pos_line );
120 : // Concatenate the three positions together
121 44 : readInputLine( getShortcutLabel() + "_pos: CONCATENATE ARG=" + getShortcutLabel() + "_cpos.x," + getShortcutLabel() + "_cpos.y," + getShortcutLabel() + "_cpos.z");
122 44 : rmsd_line += "RMSD_VECTOR ARG=" + getShortcutLabel() + "_pos," + getShortcutLabel() + "_ref";
123 22 : if( disp ) {
124 : rmsd_line += " DISPLACEMENT";
125 : }
126 : // Now align
127 22 : std::vector<double> align( pdb.getOccupancy() );
128 22 : Tools::convert( align[0], num );
129 22 : rmsd_line += " ALIGN=" + num;
130 210 : for(unsigned i=1; i<align.size(); ++i) {
131 188 : Tools::convert( align[i], num );
132 376 : rmsd_line += "," + num;
133 : }
134 : // And displace
135 22 : std::vector<double> displace( pdb.getBeta() );
136 22 : Tools::convert( displace[0], num );
137 22 : rmsd_line += " DISPLACE=" + num;
138 210 : for(unsigned i=1; i<displace.size(); ++i) {
139 188 : Tools::convert( displace[i], num );
140 376 : rmsd_line += "," + num;
141 : }
142 : }
143 : // And create the RMSD object
144 : bool numder;
145 104 : parseFlag("NUMERICAL_DERIVATIVES",numder);
146 104 : if(numder && nf==1 && !disp ) {
147 : rmsd_line += " NUMERICAL_DERIVATIVES";
148 99 : } else if( numder ) {
149 0 : error("can only use NUMERICAL_DERIVATIVES flag when RMSD is calculating a single scalar value");
150 : }
151 : bool squared;
152 105 : parseFlag("SQUARED",squared);
153 104 : if(squared) {
154 : rmsd_line += " SQUARED";
155 : }
156 : std::string tt;
157 104 : parse("TYPE",tt);
158 209 : readInputLine( rmsd_line + " TYPE=" + tt );
159 212 : }
160 :
161 : }
162 : }
|