All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
SecondaryStructureRMSD.cpp
Go to the documentation of this file.
1 /* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
2  Copyright (c) 2013 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-code.org for more information.
6 
7  This file is part of plumed, version 2.0.
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 "SecondaryStructureRMSD.h"
23 #include "core/PlumedMain.h"
24 #include "core/ActionSet.h"
25 #include "core/SetupMolInfo.h"
26 #include "core/Atoms.h"
27 #include "vesselbase/Vessel.h"
28 #include "tools/DRMSD.h"
29 #include "tools/RMSD.h"
30 
31 namespace PLMD {
32 namespace secondarystructure{
33 
38  keys.add("residues","RESIDUES","this command is used to specify the set of residues that could conceivably form part of the secondary structure. "
39  "It is possible to use residues numbers as the various chains and residues should have been identified else using an instance of the "
40  "\\ref MOLINFO action. If you wish to use all the residues from all the chains in your system you can do so by "
41  "specifying all. Alternatively, if you wish to use a subset of the residues you can specify the particular residues "
42  "you are interested in as a list of numbers. Please be aware that to form secondary structure elements your chain "
43  "must contain at least N residues, where N is dependent on the particular secondary structure you are interested in. "
44  "As such if you define portions of the chain with fewer than N residues the code will crash.");
45  keys.add("compulsory","TYPE","DRMSD","the manner in which RMSD alignment is performed. Should be OPTIMAL, SIMPLE or DRMSD. "
46  "For more details on the OPTIMAL and SIMPLE methods see \\ref RMSD. For more details on the "
47  "DRMSD method see \\ref DRMSD.");
48  keys.add("compulsory","R_0","The r_0 parameter of the switching function.");
49  keys.add("compulsory","D_0","0.0","The d_0 parameter of the switching function");
50  keys.add("compulsory","NN","8","The n parameter of the switching function");
51  keys.add("compulsory","MM","12","The m parameter of the switching function");
52  keys.reserve("optional","STRANDS_CUTOFF","If in a segment of protein the two strands are further apart then the calculation "
53  "of the actual RMSD is skipped as the structure is very far from being beta-sheet like. "
54  "This keyword speeds up the calculation enormously when you are using the LESS_THAN option. "
55  "However, if you are using some other option, then this cannot be used");
56  keys.addFlag("NOPBC",false,"ignore the periodic boundary conditions when calculating distances");
57  keys.addFlag("VERBOSE",false,"write a more detailed output");
58  keys.add("hidden","NL_STRIDE","the frequency with which the neighbor list should be updated. Between neighbour list update steps all quantities "
59  "that contributed less than TOL at the previous neighbor list update step are ignored.");
60  ActionWithVessel::registerKeywords( keys );
61  keys.setComponentsIntroduction("By default this Action calculates the number of structural units that are within a certain "
62  "distance of a idealised secondary structure element. This quantity can then be referenced "
63  "elsewhere in the input by using the label of the action. However, thes Action can also be used to "
64  "calculate the following quantities by using the keywords as described below. The quantities then "
65  "calculated can be referened using the label of the action followed by a dot and then the name "
66  "from the table below.");
67  keys.use("LESS_THAN"); keys.use("MIN");
68 }
69 
71 Action(ao),
72 ActionAtomistic(ao),
73 ActionWithValue(ao),
74 ActionWithVessel(ao),
75 updateFreq(0),
76 lastUpdate(0),
77 reduceAtNextStep(false),
78 align_strands(false),
79 s_cutoff(0),
80 align_atom_1(0),
81 align_atom_2(0)
82 {
83  parse("TYPE",alignType);
84  log.printf(" distances from secondary structure elements are calculated using %s algorithm\n",alignType.c_str() );
85  log<<" Bibliography "<<plumed.cite("Pietrucci and Laio, J. Chem. Theory Comput. 5, 2197 (2009)"); log<<"\n";
86 
87  bool nopbc; parseFlag("NOPBC",nopbc); pbcon=!nopbc;
88 
89  parseFlag("VERBOSE",verbose_output);
90  if( keywords.exists("NL_STRIDE") ) parse("NL_STRIDE",updateFreq);
91  if(updateFreq>0) log.printf(" Updating contributors every %d steps.\n",updateFreq);
92  else log.printf(" Updating contributors every step.\n");
93 
94  if( keywords.exists("STRANDS_CUTOFF") ){
95  parse("STRANDS_CUTOFF",s_cutoff); align_strands=true;
96  if( s_cutoff>0) log.printf(" ignoring contributions from strands that are more than %f apart\n",s_cutoff);
97  }
98 }
99 
101  for(unsigned i=0;i<secondary_rmsd.size();++i) delete secondary_rmsd[i];
102  for(unsigned i=0;i<secondary_drmsd.size();++i) delete secondary_drmsd[i];
103 }
104 
105 void SecondaryStructureRMSD::setAtomsFromStrands( const unsigned& atom1, const unsigned& atom2 ){
106  align_atom_1=atom1; align_atom_2=atom2;
107 }
108 
109 void SecondaryStructureRMSD::readBackboneAtoms( const std::vector<std::string>& backnames, std::vector<unsigned>& chain_lengths ){
110  std::vector<SetupMolInfo*> moldat=plumed.getActionSet().select<SetupMolInfo*>();
111  if( moldat.size()==0 ) error("Unable to find MOLINFO in input");
112 
113  std::vector<std::string> resstrings; parseVector( "RESIDUES", resstrings );
114  if( !verbose_output ){
115  if(resstrings[0]=="all"){
116  log.printf(" examining all possible secondary structure combinations");
117  } else {
118  log.printf(" examining secondary struture in residue poritions : %s ",resstrings[0].c_str() );
119  for(unsigned i=1;i<resstrings.size();++i) log.printf(", %s",resstrings[i].c_str() );
120  log.printf("\n");
121  }
122  }
123  std::vector< std::vector<AtomNumber> > backatoms;
124  moldat[0]->getBackbone( resstrings, backnames, backatoms );
125 
126  chain_lengths.resize( backatoms.size() );
127  for(unsigned i=0;i<backatoms.size();++i){
128  chain_lengths[i]=backatoms[i].size();
129  for(unsigned j=0;j<backatoms[i].size();++j) all_atoms.addIndexToList( backatoms[i][j] );
130  }
131 }
132 
133 void SecondaryStructureRMSD::addColvar( const std::vector<unsigned>& newatoms ){
134  if( colvar_atoms.size()>0 ) plumed_assert( colvar_atoms[0].size()==newatoms.size() );
135  if( verbose_output ){
136  log.printf(" Secondary structure segment %d contains atoms : ", colvar_atoms.size()+1);
137  for(unsigned i=0;i<newatoms.size();++i) log.printf("%d ",all_atoms(newatoms[i]).serial() );
138  log.printf("\n");
139  }
141  colvar_atoms.push_back( newatoms );
142 }
143 
144 void SecondaryStructureRMSD::setSecondaryStructure( std::vector<Vector>& structure, double bondlength, double units ){
145  // If we are in natural units get conversion factor from nm into natural length units
146  if( plumed.getAtoms().usingNaturalUnits() ){
147  error("cannot use this collective variable when using natural units");
148  }
149  plumed_massert( !(align_strands && align_atom_1==0 && align_atom_2==0), "you must use setAtomsFromStrands with strands cutoff");
150 
151  // Convert into correct units
152  for(unsigned i=0;i<structure.size();++i){
153  structure[i][0]*=units; structure[i][1]*=units; structure[i][2]*=units;
154  }
155 
156  if( secondary_rmsd.size()==0 && secondary_drmsd.size()==0 ){
157  pos.resize( structure.size() ); taskList.activateAll();
158  for(unsigned i=0;i<taskList.getNumberActive();++i){
159  for(unsigned j=0;j<colvar_atoms[i].size();++j) all_atoms.activate( colvar_atoms[i][j] );
160  }
161  all_atoms.updateActiveMembers();
162  ActionAtomistic::requestAtoms( all_atoms.retrieveActiveList() );
164 
166  if( getNumberOfVessels()==0 ){
167  double r0; parse("R_0",r0); double d0; parse("D_0",d0);
168  int nn; parse("NN",nn); int mm; parse("MM",mm);
169  std::ostringstream ostr;
170  ostr<<"RATIONAL R_0="<<r0<<" D_0="<<d0<<" NN="<<nn<<" MM="<<mm;
171  std::string input=ostr.str(); addVessel( "LESS_THAN", input, -1 ); // -1 here means that this value will be named getLabel()
172  readVesselKeywords(); // This makes sure resizing is done
173  }
174  }
175 
176  // Set the reference structure
177  std::vector<Vector> tmp( structure.size() ); der.push_back( tmp );
178  vir.push_back( Tensor() );
179  if( alignType=="DRMSD" ){
180  secondary_drmsd.push_back( new DRMSD() );
181  secondary_drmsd[secondary_drmsd.size()-1]->setReference( structure, bondlength );
182  } else {
183  std::vector<double> align( structure.size(), 1.0 );
184  secondary_rmsd.push_back( new RMSD(log) );
185  secondary_rmsd[secondary_rmsd.size()-1]->setType( alignType );
186  secondary_rmsd[secondary_rmsd.size()-1]->setReference( structure );
187  secondary_rmsd[secondary_rmsd.size()-1]->setAlign( align );
188  secondary_rmsd[secondary_rmsd.size()-1]->setDisplace( align );
189  }
190 // references.push_back( PLMD::SingleDomainRMSD::create( this, alignType ) );
191 // unsigned nn=references.size()-1;
192 // std::vector<double> align( structure.size(), 1.0 ), displace( structure.size(), 1.0 );
193 // references[nn]->setBoundsOnDistances( true , bondlength ); // We always use pbc
194 // references[nn]->setReference( structure, align, displace );
195 // references[nn]->setNumberOfAtoms( structure.size() );
196 }
197 
199  bool updatetime=false;
200  if( reduceAtNextStep ){
202  reduceAtNextStep=false; updatetime=true;
203  }
204  if( updateFreq>0 && (getStep()-lastUpdate)>=updateFreq ){
206  reduceAtNextStep=true; updatetime=true;
208  }
209  if(updatetime){
210  for(unsigned i=0;i<taskList.getNumberActive();++i){
211  for(unsigned j=0;j<colvar_atoms[i].size();++j) all_atoms.activate( colvar_atoms[i][j] );
212  }
213  all_atoms.updateActiveMembers();
214  ActionAtomistic::requestAtoms( all_atoms.retrieveActiveList() );
216  resizeFunctions();
217  }
218 }
219 
221  runAllTasks();
222 }
223 
224 void SecondaryStructureRMSD::performTask( const unsigned& j ){
225  // Retrieve the positions
226  for(unsigned i=0;i<pos.size();++i) pos[i]=ActionAtomistic::getPosition( getAtomIndex(i) );
227 
228  // This does strands cutoff
230  if( s_cutoff>0 ){
231  if( distance.modulo()>s_cutoff ){
232  setElementValue(1,0.0);
233  return;
234  }
235  }
236 
237  // This aligns the two strands if this is required
238  if( alignType!="DRMSD" && align_strands ){
239  Vector origin_old, origin_new; origin_old=pos[align_atom_2];
240  origin_new=pos[align_atom_1]+distance;
241  for(unsigned i=15;i<30;++i){
242  pos[i]+=( origin_new - origin_old );
243  }
244  }
245 
246  // And now calculate the RMSD
247  closest=0; double r, nr;
248  if( secondary_drmsd.size()>0 ){
249  if( pbcon ) r=secondary_drmsd[0]->calculate( pos, getPbc(), der[0], vir[0] );
250  else r=secondary_drmsd[0]->calculate( pos, der[0], vir[0] );
251  for(unsigned i=1;i<secondary_drmsd.size();++i){
252  if( pbcon ) nr=secondary_drmsd[i]->calculate( pos, getPbc(), der[i], vir[i] );
253  else nr=secondary_drmsd[i]->calculate( pos, der[i], vir[i] );
254  if(nr<r){ closest=i; r=nr; }
255  }
256  } else {
257  r=secondary_rmsd[0]->calculate( pos, der[0] );
258  for(unsigned i=1;i<secondary_rmsd.size();++i){
259  nr=secondary_rmsd[i]->calculate( pos, der[i] );
260  if( nr<r ){ closest=i; r=nr; }
261  }
262  }
263  setElementValue(1,1.0); setElementValue(0,r);
264  return;
265 }
266 
267 void SecondaryStructureRMSD::mergeDerivatives( const unsigned& ider, const double& df ){
268  plumed_dbg_assert( ider==0 );
269  for(unsigned i=0;i<colvar_atoms[current].size();++i){
270  unsigned thisatom=getAtomIndex(i), thispos=3*thisatom;
271  Vector ader=der[closest][i];
272  accumulateDerivative( thispos, df*ader[0] ); thispos++;
273  accumulateDerivative( thispos, df*ader[1] ); thispos++;
274  accumulateDerivative( thispos, df*ader[2] );
275  }
276  if( alignType!="DRMSD" ){
277  vir[closest].zero();
278  for(unsigned i=0;i<colvar_atoms[current].size();++i){
279  vir[closest]+=(-1.0*Tensor( pos[i], der[closest][i] ));
280  }
281  }
282 
283  // Easy to merge the virial
284  unsigned outnat=3*getNumberOfAtoms();
285  accumulateDerivative( outnat, df*vir[closest](0,0) ); outnat++;
286  accumulateDerivative( outnat, df*vir[closest](0,1) ); outnat++;
287  accumulateDerivative( outnat, df*vir[closest](0,2) ); outnat++;
288  accumulateDerivative( outnat, df*vir[closest](1,0) ); outnat++;
289  accumulateDerivative( outnat, df*vir[closest](1,1) ); outnat++;
290  accumulateDerivative( outnat, df*vir[closest](1,2) ); outnat++;
291  accumulateDerivative( outnat, df*vir[closest](2,0) ); outnat++;
292  accumulateDerivative( outnat, df*vir[closest](2,1) ); outnat++;
293  accumulateDerivative( outnat, df*vir[closest](2,2) );
294 }
295 
298 }
299 
300 }
301 }
void setComponentsIntroduction(const std::string &instr)
Set the text that introduces how the components for this action are introduced.
Definition: Keywords.cpp:561
const Vector & getPosition(int) const
Get position of i-th atom.
static void registerKeywords(Keywords &keys)
Register all the relevant keywords for the action.
void parseFlag(const std::string &key, bool &t)
Parse one keyword as boolean flag.
Definition: Action.cpp:104
unsigned current
The numerical index of the task we are curently performing.
void setSecondaryStructure(std::vector< Vector > &structure, double bondlength, double units)
Set a reference configuration.
Log & log
Reference to the log stream.
Definition: Action.h:93
static void registerKeywords(Keywords &keys)
double modulo() const
Compute the modulo.
Definition: Vector.h:325
Class implementing fixed size vectors of doubles.
Definition: Vector.h:74
void error(const std::string &msg) const
Crash calculation and print documentation.
Definition: Action.cpp:195
std::vector< Vector > pos
Tempory variables for getting positions of atoms and applying forces.
int updateFreq
Everything for controlling the updating of neighbor lists.
void add(const std::string &t, const std::string &k, const std::string &d)
Add a new keyword of type t with name k and description d.
Definition: Keywords.cpp:167
void addVessel(const std::string &name, const std::string &input, const int numlab=0, const std::string thislab="")
Add a vessel to the list of vessels.
Communicator & comm
Definition: Action.h:158
void readBackboneAtoms(const std::vector< std::string > &backnames, std::vector< unsigned > &chain_lengths)
Get the atoms in the backbone.
std::string alignType
The type of rmsd we are calculating.
void runAllTasks()
Calculate the values of all the vessels.
A class that implements RMSD calculations This is a class that implements the various infrastructure ...
Definition: RMSD.h:62
bool getForcesFromVessels(std::vector< double > &forcesToApply)
Retrieve the forces from all the vessels (used in apply)
std::vector< std::vector< Vector > > der
Stuff for derivatives.
void readVesselKeywords()
Complete the setup of this object (this routine must be called after construction of ActionWithValue)...
const Pbc & getPbc() const
Get reference to Pbc.
void addColvar(const std::vector< unsigned > &newatoms)
Add a set of atoms to calculat ethe rmsd from.
unsigned getAtomIndex(const unsigned &iatom)
Get the index of an atom.
Used to create a PLMD::Action that has some scalar or vectorial output that may or may not have some ...
DynamicList< AtomNumber > all_atoms
List of all the atoms we require.
void parse(const std::string &key, T &t)
Parse one keyword as generic type.
Definition: Action.h:273
This class holds the keywords and their documentation.
Definition: Keywords.h:36
This class is used to bring the relevant information to the Action constructor.
Definition: Action.h:41
Action used to create objects that access the positions of the atoms from the MD code.
void addIndexToList(const T &ii)
Add something to the active list.
Definition: DynamicList.h:235
int printf(const char *fmt,...)
Formatted output with explicit format - a la printf.
Definition: OFile.cpp:82
void setElementValue(const unsigned &, const double &)
Set the value of the element.
Base class for all the input Actions.
Definition: Action.h:60
static void registerKeywords(Keywords &keys)
Register all the relevant keywords for the action.
Definition: Action.cpp:49
void parseVector(const std::string &key, std::vector< T > &t)
Parse one keyword as std::vector.
Definition: Action.h:311
void accumulateDerivative(const unsigned &ider, const double &df)
This is used to accumulate the derivatives when we merge using chainRuleForElementDerivatives.
void reserve(const std::string &t, const std::string &k, const std::string &d, const bool isvessel=false)
Reserve a keyword.
Definition: Keywords.cpp:110
void use(const std::string &k)
Use one of the reserved keywords.
Definition: Keywords.cpp:154
DynamicList< unsigned > taskList
The list of tasks we have to perform.
A class that implements DRMSD calculations.
Definition: DRMSD.h:37
unsigned getNumberOfVessels() const
Get the number of vessels.
bool align_strands
Variables for strands cutoff.
long int getStep() const
Return the present timestep.
Definition: Action.cpp:169
bool exists(const std::string &k) const
Check if there is a keyword with name k.
Definition: Keywords.cpp:239
friend void mpi_gatherActiveMembers(Communicator &, std::vector< DynamicList< U > > &)
This gathers data split across nodes list of Dynamic lists.
Definition: DynamicList.h:318
Vector pbcDistance(const Vector &, const Vector &) const
Compute the pbc distance between two positions.
void requestAtoms(const std::vector< AtomNumber > &a)
Request an array of atoms.
Main plumed object.
Definition: Plumed.h:201
void performTask(const unsigned &j)
Calculate one of the functions in the distribution.
void mergeDerivatives(const unsigned &, const double &)
bool serial
Do all calculations in serial.
void setForcesOnAtoms(const std::vector< double > &forcesToApply, unsigned ind=0)
Add the forces to the atoms.
Tensor3d Tensor
Definition: Tensor.h:425
unsigned getNumberOfAtoms() const
Get number of available atoms.
void setAtomsFromStrands(const unsigned &atom1, const unsigned &atom2)
Setup a pair of atoms to use for strands cutoff.
std::vector< RMSD * > secondary_rmsd
The reference configurations.
const Keywords & keywords
Definition: Action.h:161
void resizeFunctions()
Resize all the functions when the number of derivatives change.
void activateAll()
Make everything in the list active.
Definition: DynamicList.h:270
unsigned closest
Tempory integer to say which refernce configuration is the closest.
std::vector< std::vector< unsigned > > colvar_atoms
The atoms involved in each of the secondary structure segments.
unsigned getNumberActive() const
Return the number of elements that are currently active.
Definition: DynamicList.h:230
void prepare()
Prepare an Action for calculation This can be used by Action if they need some special preparation be...
void addFlag(const std::string &k, const bool def, const std::string &d)
Add a falg with name k that is by default on if def is true and off if def is false. d should provide a description of the flag.
Definition: Keywords.cpp:193