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