Line data Source code
1 : /* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 : Copyright (c) 2012-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 "Colvar.h" 23 : #include "core/PlumedMain.h" 24 : #include "ActionRegister.h" 25 : #include "tools/PDB.h" 26 : #include "reference/DRMSD.h" 27 : #include "reference/MetricRegister.h" 28 : #include "core/Atoms.h" 29 : #include <memory> 30 : 31 : using namespace std; 32 : 33 : namespace PLMD { 34 : namespace colvar { 35 : 36 : //+PLUMEDOC DCOLVAR DRMSD 37 : /* 38 : Calculate the distance RMSD with respect to a reference structure. 39 : 40 : To calculate the root-mean-square deviation between the atoms in two configurations 41 : you must first superimpose the two structures in some ways. Obviously, it is the internal vibrational 42 : motions of the structure - i.e. not the translations and rotations - that are interesting. However, 43 : aligning two structures by removing the translational and rotational motions is not easy. Furthermore, 44 : in some cases there can be alignment issues caused by so-called frame-fitting problems. It is thus 45 : often cheaper and easier to calculate the distances between all the pairs of atoms. The distance 46 : between the two structures, \f$\mathbf{X}^a\f$ and \f$\mathbf{X}^b\f$ can then be measured as: 47 : 48 : \f[ 49 : d(\mathbf{X}^A, \mathbf{X}^B) = \sqrt{\frac{1}{N(N-1)} \sum_{i \ne j} [ d(\mathbf{x}_i^a,\mathbf{x}_j^a) - d(\mathbf{x}_i^b,\mathbf{x}_j^b) ]^2} 50 : \f] 51 : 52 : where \f$N\f$ is the number of atoms and \f$d(\mathbf{x}_i,\mathbf{x}_j)\f$ represents the distance between 53 : atoms \f$i\f$ and \f$j\f$. Clearly, this representation of the configuration is invariant to translation and rotation. 54 : However, it can become expensive to calculate when the number of atoms is large. This can be resolved 55 : within the DRMSD colvar by setting LOWER_CUTOFF and UPPER_CUTOFF. These keywords ensure that only 56 : pairs of atoms that are within a certain range are incorporated into the above sum. 57 : 58 : In PDB files the atomic coordinates and box lengths should be in Angstroms unless 59 : you are working with natural units. If you are working with natural units then the coordinates 60 : should be in your natural length unit. For more details on the PDB file format visit http://www.wwpdb.org/docs.html 61 : 62 : \par Examples 63 : 64 : The following tells plumed to calculate the distance RMSD between 65 : the positions of the atoms in the reference file and their instantaneous 66 : position. Only pairs of atoms whose distance in the reference structure is within 67 : 0.1 and 0.8 nm are considered. 68 : 69 : \plumedfile 70 : DRMSD REFERENCE=file1.pdb LOWER_CUTOFF=0.1 UPPER_CUTOFF=0.8 71 : \endplumedfile 72 : 73 : The reference file is a PDB file that looks like this 74 : 75 : \auxfile{file1.pdb} 76 : ATOM 8 HT3 ALA 2 -1.480 -1.560 1.212 1.00 1.00 DIA H 77 : ATOM 9 CAY ALA 2 -0.096 2.144 -0.669 1.00 1.00 DIA C 78 : ATOM 10 HY1 ALA 2 0.871 2.385 -0.588 1.00 1.00 DIA H 79 : ATOM 12 HY3 ALA 2 -0.520 2.679 -1.400 1.00 1.00 DIA H 80 : ATOM 14 OY ALA 2 -1.139 0.931 -0.973 1.00 1.00 DIA O 81 : END 82 : \endauxfile 83 : 84 : The following tells plumed to calculate a DRMSD value for a pair of molecules. 85 : 86 : \plumedfile 87 : DRMSD REFERENCE=file2.pdb LOWER_CUTOFF=0.1 UPPER_CUTOFF=0.8 TYPE=INTER-DRMSD 88 : \endplumedfile 89 : 90 : In the input reference file (file.pdb) the atoms in each of the two molecules are separated by a TER 91 : command as shown below. 92 : 93 : \auxfile{file2.pdb} 94 : ATOM 8 HT3 ALA 2 -1.480 -1.560 1.212 1.00 1.00 DIA H 95 : ATOM 9 CAY ALA 2 -0.096 2.144 -0.669 1.00 1.00 DIA C 96 : ATOM 10 HY1 ALA 2 0.871 2.385 -0.588 1.00 1.00 DIA H 97 : TER 98 : ATOM 12 HY3 ALA 2 -0.520 2.679 -1.400 1.00 1.00 DIA H 99 : ATOM 14 OY ALA 2 -1.139 0.931 -0.973 1.00 1.00 DIA O 100 : END 101 : \endauxfile 102 : 103 : In this example the INTER-DRMSD type ensures that the set of distances from which the final 104 : quantity is computed involve one atom from each of the two molecules. If this is replaced 105 : by INTRA-DRMSD then only those distances involving pairs of atoms that are both in the same 106 : molecule are computed. 107 : 108 : */ 109 : //+ENDPLUMEDOC 110 : 111 : 112 33 : class DRMSD : public Colvar { 113 : 114 : bool pbc_; 115 : MultiValue myvals; 116 : ReferenceValuePack mypack; 117 : std::unique_ptr<PLMD::DRMSD> drmsd_; 118 : 119 : public: 120 : explicit DRMSD(const ActionOptions&); 121 : virtual void calculate(); 122 : static void registerKeywords(Keywords& keys); 123 : }; 124 : 125 7379 : PLUMED_REGISTER_ACTION(DRMSD,"DRMSD") 126 : 127 13 : void DRMSD::registerKeywords(Keywords& keys) { 128 13 : Colvar::registerKeywords(keys); 129 52 : keys.add("compulsory","REFERENCE","a file in pdb format containing the reference structure and the atoms involved in the CV."); 130 52 : keys.add("compulsory","LOWER_CUTOFF","only pairs of atoms further than LOWER_CUTOFF are considered in the calculation."); 131 52 : keys.add("compulsory","UPPER_CUTOFF","only pairs of atoms closer than UPPER_CUTOFF are considered in the calculation."); 132 65 : keys.add("compulsory","TYPE","DRMSD","what kind of DRMSD would you like to calculate. You can use either the normal DRMSD involving all the distances between " 133 : "the atoms in your molecule. Alternatively, if you have multiple molecules you can use the type INTER-DRMSD " 134 : "to compute DRMSD values involving only those distances between the atoms at least two molecules or the type INTRA-DRMSD " 135 : "to compute DRMSD values involving only those distances between atoms in the same molecule"); 136 13 : } 137 : 138 12 : DRMSD::DRMSD(const ActionOptions&ao): 139 13 : PLUMED_COLVAR_INIT(ao), pbc_(true), myvals(1,0), mypack(0,0,myvals) 140 : { 141 : string reference; 142 24 : parse("REFERENCE",reference); 143 : double lcutoff; 144 24 : parse("LOWER_CUTOFF",lcutoff); 145 : double ucutoff; 146 24 : parse("UPPER_CUTOFF",ucutoff); 147 12 : bool nopbc(false); 148 24 : parseFlag("NOPBC",nopbc); 149 12 : pbc_=!nopbc; 150 : 151 12 : addValueWithDerivatives(); setNotPeriodic(); 152 : 153 : // read everything in ang and transform to nm if we are not in natural units 154 24 : PDB pdb; 155 24 : if( !pdb.read(reference,plumed.getAtoms().usingNaturalUnits(),0.1/atoms.getUnits().getLength()) ) 156 2 : error("missing input file " + reference ); 157 : 158 : // store target_ distance 159 22 : std::string type; parse("TYPE",type); 160 22 : drmsd_=metricRegister().create<PLMD::DRMSD>( type ); 161 11 : drmsd_->setBoundsOnDistances( !nopbc, lcutoff, ucutoff ); 162 11 : drmsd_->read( pdb ); 163 11 : checkRead(); 164 : 165 : std::vector<AtomNumber> atoms; 166 11 : drmsd_->getAtomRequests( atoms ); 167 : // drmsd_->setNumberOfAtoms( atoms.size() ); 168 11 : requestAtoms( atoms ); 169 : 170 : // Setup the derivative pack 171 22 : myvals.resize( 1, 3*atoms.size()+9 ); mypack.resize( 0, atoms.size() ); 172 376 : for(unsigned i=0; i<atoms.size(); ++i) mypack.setAtomIndex( i, i ); 173 : 174 22 : log.printf(" reference from file %s\n",reference.c_str()); 175 22 : log.printf(" which contains %d atoms\n",getNumberOfAtoms()); 176 11 : log.printf(" with indices : "); 177 376 : for(unsigned i=0; i<atoms.size(); ++i) { 178 118 : if(i%25==0) log<<"\n"; 179 236 : log.printf("%d ",atoms[i].serial()); 180 : } 181 11 : log.printf("\n"); 182 11 : } 183 : 184 : // calculator 185 595 : void DRMSD::calculate() { 186 : 187 595 : double drmsd; Tensor virial; mypack.clear(); 188 1190 : drmsd=drmsd_->calculate(getPositions(), getPbc(), mypack, false); 189 : 190 595 : setValue(drmsd); 191 27185 : for(unsigned i=0; i<getNumberOfAtoms(); ++i) { if( myvals.isActive(3*i) ) setAtomsDerivatives( i, mypack.getAtomDerivative(i) ); } 192 1190 : setBoxDerivatives( mypack.getBoxDerivatives() ); 193 595 : } 194 : 195 : } 196 5517 : }